mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-07-20 23:00:29 -04:00
!265 sync code to ohos master
Merge pull request !265 from zhangyukun8/master
This commit is contained in:
@@ -28,14 +28,10 @@ group("ark_js_packages") {
|
||||
group("ark_js_host_linux_tools_packages") {
|
||||
deps = []
|
||||
if (host_os != "mac") {
|
||||
deps += [
|
||||
"//ark/js_runtime:libark_jsruntime(${host_toolchain})",
|
||||
"//ark/js_runtime/ecmascript/js_vm:ark_js_vm(${host_toolchain})",
|
||||
]
|
||||
deps += [ "//ark/js_runtime/ecmascript/js_vm:ark_js_vm(${host_toolchain})" ]
|
||||
if (is_standard_system) {
|
||||
deps += [
|
||||
"//ark/js_runtime/ecmascript/compiler:ark_stub_opt(${host_toolchain})",
|
||||
"//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer(${host_toolchain})",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -48,6 +44,7 @@ group("ark_js_unittest") {
|
||||
deps += [
|
||||
"//ark/js_runtime/ecmascript/builtins/tests:unittest",
|
||||
"//ark/js_runtime/ecmascript/hprof/tests:unittest",
|
||||
"//ark/js_runtime/ecmascript/ic/tests:unittest",
|
||||
"//ark/js_runtime/ecmascript/napi/test:unittest",
|
||||
"//ark/js_runtime/ecmascript/regexp/tests:unittest",
|
||||
"//ark/js_runtime/ecmascript/snapshot/tests:unittest",
|
||||
@@ -63,10 +60,9 @@ group("ark_js_host_unittest") {
|
||||
if (host_os != "mac") {
|
||||
# js unittest
|
||||
deps += [
|
||||
"//ark/js_runtime:libark_jsruntime(${host_toolchain})",
|
||||
"//ark/js_runtime/ecmascript/builtins/tests:host_unittest",
|
||||
"//ark/js_runtime/ecmascript/hprof/tests:host_unittest",
|
||||
"//ark/js_runtime/ecmascript/js_vm:ark_js_vm(${host_toolchain})",
|
||||
"//ark/js_runtime/ecmascript/ic/tests:host_unittest",
|
||||
"//ark/js_runtime/ecmascript/napi/test:host_unittest",
|
||||
"//ark/js_runtime/ecmascript/regexp/tests:host_unittest",
|
||||
"//ark/js_runtime/ecmascript/snapshot/tests:host_unittest",
|
||||
@@ -135,6 +131,9 @@ config("ark_jsruntime_common_config") {
|
||||
if (enable_stub_aot) {
|
||||
defines += [ "ECMASCRIPT_ENABLE_STUB_AOT" ]
|
||||
}
|
||||
if (enable_specific_stubs) {
|
||||
defines += [ "ECMASCRIPT_ENABLE_SPECIFIC_STUBS" ]
|
||||
}
|
||||
|
||||
if (is_standard_system) {
|
||||
defines += [ "IS_STANDARD_SYSTEM" ]
|
||||
@@ -175,10 +174,12 @@ config("ark_jsruntime_common_config") {
|
||||
"-pipe",
|
||||
"-Wdate-time",
|
||||
"-Wformat=2",
|
||||
"-flto",
|
||||
]
|
||||
|
||||
ldflags = [ "-flto" ]
|
||||
if (!use_libfuzzer) {
|
||||
cflags_cc += [ "-flto" ]
|
||||
ldflags = [ "-flto" ]
|
||||
}
|
||||
|
||||
if (is_debug) {
|
||||
cflags_cc += [
|
||||
@@ -203,6 +204,7 @@ config("ark_jsruntime_common_config") {
|
||||
defines += [
|
||||
"PANDA_TARGET_ARM32_ABI_SOFT=1",
|
||||
"PANDA_TARGET_ARM32",
|
||||
"PANDA_TARGET_32",
|
||||
]
|
||||
} else if (current_cpu == "arm64") {
|
||||
defines += [
|
||||
@@ -279,6 +281,9 @@ ecma_source = [
|
||||
"ecmascript/builtins/builtins_weak_map.cpp",
|
||||
"ecmascript/builtins/builtins_weak_set.cpp",
|
||||
"ecmascript/class_linker/panda_file_translator.cpp",
|
||||
"ecmascript/cpu_profiler/cpu_profiler.cpp",
|
||||
"ecmascript/cpu_profiler/profile_processor.cpp",
|
||||
"ecmascript/cpu_profiler/profile_generator.cpp",
|
||||
"ecmascript/dump.cpp",
|
||||
"ecmascript/ecma_class_linker_extension.cpp",
|
||||
"ecmascript/ecma_exceptions.cpp",
|
||||
@@ -298,8 +303,10 @@ ecma_source = [
|
||||
"ecmascript/hprof/heap_snapshot_json_serializer.cpp",
|
||||
"ecmascript/hprof/heap_tracker.cpp",
|
||||
"ecmascript/hprof/string_hashmap.cpp",
|
||||
"ecmascript/ic/profile_type_info.cpp",
|
||||
"ecmascript/ic/ic_runtime.cpp",
|
||||
"ecmascript/ic/ic_compare_op.cpp",
|
||||
"ecmascript/ic/invoke_cache.cpp",
|
||||
"ecmascript/ic/profile_type_info.cpp",
|
||||
"ecmascript/ic/property_box.cpp",
|
||||
"ecmascript/ic/proto_change_details.cpp",
|
||||
"ecmascript/internal_call_params.cpp",
|
||||
@@ -342,20 +349,22 @@ ecma_source = [
|
||||
"ecmascript/mem/c_string.cpp",
|
||||
"ecmascript/mem/chunk.cpp",
|
||||
"ecmascript/mem/compress_collector.cpp",
|
||||
"ecmascript/mem/concurrent_marker.cpp",
|
||||
"ecmascript/mem/concurrent_sweeper.cpp",
|
||||
"ecmascript/mem/ecma_heap_manager.cpp",
|
||||
"ecmascript/mem/evacuation_allocator.cpp",
|
||||
"ecmascript/mem/free_object_kind.cpp",
|
||||
"ecmascript/mem/free_object_list.cpp",
|
||||
"ecmascript/mem/gc_stats.cpp",
|
||||
"ecmascript/mem/heap.cpp",
|
||||
"ecmascript/mem/mem_controller.cpp",
|
||||
"ecmascript/mem/old_space_collector.cpp",
|
||||
"ecmascript/mem/mix_space_collector.cpp",
|
||||
"ecmascript/mem/parallel_work_helper.cpp",
|
||||
"ecmascript/mem/parallel_evacuation.cpp",
|
||||
"ecmascript/mem/parallel_marker.cpp",
|
||||
"ecmascript/mem/region_factory.cpp",
|
||||
"ecmascript/mem/semi_space_collector.cpp",
|
||||
"ecmascript/mem/semi_space_marker.cpp",
|
||||
"ecmascript/mem/semi_space_worker.cpp",
|
||||
"ecmascript/mem/space.cpp",
|
||||
"ecmascript/mem/tagged_object.cpp",
|
||||
"ecmascript/mem/verification.cpp",
|
||||
"ecmascript/napi/jsnapi.cpp",
|
||||
"ecmascript/object_factory.cpp",
|
||||
@@ -369,6 +378,7 @@ ecma_source = [
|
||||
"ecmascript/regexp/regexp_opcode.cpp",
|
||||
"ecmascript/regexp/regexp_parser.cpp",
|
||||
"ecmascript/regexp/regexp_parser_cache.cpp",
|
||||
"ecmascript/runtime_api.cpp",
|
||||
"ecmascript/runtime_trampolines.cpp",
|
||||
"ecmascript/snapshot/mem/slot_bit.cpp",
|
||||
"ecmascript/snapshot/mem/snapshot.cpp",
|
||||
@@ -420,10 +430,10 @@ ohos_shared_library("libark_jsruntime") {
|
||||
deps = [
|
||||
":libark_js_intl_static",
|
||||
":libark_jsruntime_static",
|
||||
"//third_party/icu/icu4c:shared_icui18n",
|
||||
"//third_party/icu/icu4c:shared_icuuc",
|
||||
]
|
||||
|
||||
configs = [ ":ark_jsruntime_config" ]
|
||||
|
||||
install_enable = true
|
||||
part_name = "ark_js_runtime"
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ For more infomation, see: [ARK Runtime Subsystem](https://gitee.com/openharmony/
|
||||
│ ├─ builtins # ECMAScript library
|
||||
│ ├─ class_linker # Bytecode pre-processing module
|
||||
│ ├─ compiler # JS compiler
|
||||
│ ├─ cpu_profiler # CPU Performance Analyzer
|
||||
│ ├─ hprof # Memory analysis utility class
|
||||
│ ├─ ic # Inline cache module
|
||||
│ ├─ interpreter # JS interpreter
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
│ ├─ builtins # ECMAScript标准库
|
||||
│ ├─ class_linker # 字节码预处理模块
|
||||
│ ├─ compiler # JS编译器
|
||||
│ ├─ cpu_profiler # CPU性能分析器
|
||||
│ ├─ hprof # 内存分析工具
|
||||
│ ├─ ic # 内联缓存模块
|
||||
│ ├─ interpreter # JS解释器
|
||||
|
||||
@@ -20,9 +20,40 @@ namespace panda::ecmascript {
|
||||
#define ARK_INLINE __attribute__((always_inline))
|
||||
#define ARK_NOINLINE __attribute__((noinline))
|
||||
|
||||
#define ECMASCRIPT_ENABLE_DEBUG_MODE 0
|
||||
#define ECMASCRIPT_ENABLE_RUNTIME_STAT 0 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define ECMASCRIPT_ENABLE_IC 1 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define ECMASCRIPT_ENABLE_THREAD_CHECK 0
|
||||
|
||||
/*
|
||||
* 1. close ic
|
||||
* 2. close parallel gc
|
||||
* 3. enable gc logs
|
||||
* 4. enable handle-scope zap, zap reclaimed regions
|
||||
* 5. switch gc mode to full gc
|
||||
* 6. enable Cast() check
|
||||
* 7. enable verify heap
|
||||
* 9. enable Proactively interrogating and collecting information in the call stack
|
||||
*/
|
||||
#if ECMASCRIPT_ENABLE_DEBUG_MODE
|
||||
#define ECMASCRIPT_ENABLE_IC 0
|
||||
#define ECMASCRIPT_DISABLE_PARALLEL_GC 1
|
||||
#define ECMASCRIPT_ENABLE_GC_LOG 1
|
||||
#define ECMASCRIPT_ENABLE_ZAP_MEM 1
|
||||
#define ECMASCRIPT_SWITCH_GC_MODE_TO_COMPRESS_GC 1
|
||||
#define ECMASCRIPT_ENABLE_CAST_CHECK 1
|
||||
#define ECMASCRIPT_ENABLE_HEAP_VERIFY 1
|
||||
#define ECMASCRIPT_ENABLE_THREAD_CHECK 1
|
||||
#define ECMASCRIPT_ENABLE_ACTIVE_CPUPROFILER 0
|
||||
#else
|
||||
#define ECMASCRIPT_ENABLE_IC 1
|
||||
#define ECMASCRIPT_DISABLE_PARALLEL_GC 0
|
||||
#define ECMASCRIPT_ENABLE_GC_LOG 0
|
||||
#define ECMASCRIPT_ENABLE_ZAP_MEM 0
|
||||
#define ECMASCRIPT_SWITCH_GC_MODE_TO_COMPRESS_GC 0
|
||||
#define ECMASCRIPT_ENABLE_CAST_CHECK 0
|
||||
#define ECMASCRIPT_ENABLE_HEAP_VERIFY 0
|
||||
#define ECMASCRIPT_ENABLE_THREAD_CHECK 0
|
||||
#define ECMASCRIPT_ENABLE_ACTIVE_CPUPROFILER 0
|
||||
#endif
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // ECMASCRIPT_BASE_CONFIG_H
|
||||
|
||||
@@ -665,7 +665,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
JSHandle<JSHClass> jsHclass(thread_, obj->GetJSHClass());
|
||||
JSTaggedValue enumCache = jsHclass->GetEnumCache();
|
||||
if (!enumCache.IsNull()) {
|
||||
int propsNumber = jsHclass->GetPropertiesNumber();
|
||||
int propsNumber = jsHclass->NumberOfProps();
|
||||
JSHandle<TaggedArray> cache(thread_, enumCache);
|
||||
uint32_t length = cache->GetLength();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
@@ -675,13 +675,13 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
}
|
||||
handleKey_.Update(key);
|
||||
JSTaggedValue value;
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetAttributes().GetTaggedObject());
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
|
||||
int index = layoutInfo->FindElementWithCache(thread_, *jsHclass, key, propsNumber);
|
||||
PropertyAttributes attr(layoutInfo->GetAttr(index));
|
||||
ASSERT(static_cast<int>(attr.GetOffset()) == index);
|
||||
value = attr.IsInlinedProps()
|
||||
? obj->GetPropertyInlinedProps(index)
|
||||
: propertiesArr->Get(index - JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS);
|
||||
: propertiesArr->Get(index - jsHclass->GetInlinedProperties());
|
||||
if (UNLIKELY(value.IsAccessor())) {
|
||||
value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()),
|
||||
JSHandle<JSTaggedValue>(obj));
|
||||
@@ -692,13 +692,13 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
}
|
||||
return hasContent;
|
||||
}
|
||||
int end = jsHclass->GetPropertiesNumber();
|
||||
int end = jsHclass->NumberOfProps();
|
||||
if (end <= 0) {
|
||||
return hasContent;
|
||||
}
|
||||
int propsNumber = jsHclass->GetPropertiesNumber();
|
||||
int propsNumber = jsHclass->NumberOfProps();
|
||||
for (int i = 0; i < end; i++) {
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetAttributes().GetTaggedObject());
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
|
||||
JSTaggedValue key = layoutInfo->GetKey(i);
|
||||
if (key.IsString() && layoutInfo->GetAttr(i).IsEnumerable()) {
|
||||
handleKey_.Update(key);
|
||||
@@ -708,7 +708,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle<JSObject> &obj, const JSHandl
|
||||
ASSERT(static_cast<int>(attr.GetOffset()) == index);
|
||||
value = attr.IsInlinedProps()
|
||||
? obj->GetPropertyInlinedProps(index)
|
||||
: propertiesArr->Get(index - JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS);
|
||||
: propertiesArr->Get(index - jsHclass->GetInlinedProperties());
|
||||
if (UNLIKELY(value.IsAccessor())) {
|
||||
value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()),
|
||||
JSHandle<JSTaggedValue>(obj));
|
||||
|
||||
@@ -154,7 +154,8 @@ void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread)
|
||||
|
||||
// GLobalObject.prototype_or_dynclass
|
||||
JSHandle<JSHClass> globalObjFuncDynclass =
|
||||
factory_->NewEcmaDynClass(JSObject::SIZE, JSType::JS_GLOBAL_OBJECT, objFuncPrototypeVal);
|
||||
factory_->NewEcmaDynClass(JSObject::SIZE, JSType::JS_GLOBAL_OBJECT, 0);
|
||||
globalObjFuncDynclass->SetPrototype(thread_, objFuncPrototypeVal.GetTaggedValue());
|
||||
globalObjFuncDynclass->SetIsDictionaryMode(true);
|
||||
// Function.prototype_or_dynclass
|
||||
JSHandle<JSHClass> emptyFuncDynclass(
|
||||
@@ -1586,7 +1587,7 @@ void Builtins::InitializeArray(const JSHandle<GlobalEnv> &env, const JSHandle<JS
|
||||
// Set the [[Realm]] internal slot of F to the running execution context's Realm
|
||||
JSHandle<LexicalEnv> lexicalEnv = factory_->NewLexicalEnv(0);
|
||||
lexicalEnv->SetParentEnv(thread_, env.GetTaggedValue());
|
||||
arrayFuncFunction->SetLexicalEnv(thread_, lexicalEnv.GetTaggedValue(), SKIP_BARRIER);
|
||||
arrayFuncFunction->SetLexicalEnv(thread_, lexicalEnv.GetTaggedValue());
|
||||
|
||||
arrayFuncFunction->SetFunctionPrototype(thread_, arrFuncInstanceDynclass.GetTaggedValue());
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ JSTaggedValue BuiltinsMap::MapConstructor(EcmaRuntimeCallInfo *argv)
|
||||
JSHandle<JSMap> map = JSHandle<JSMap>::Cast(obj);
|
||||
|
||||
// 4.Set map’s [[MapData]] internal slot to a new empty List.
|
||||
JSTaggedValue linkedMap = LinkedHashMap::Create(thread);
|
||||
JSHandle<LinkedHashMap> linkedMap = LinkedHashMap::Create(thread);
|
||||
map->SetLinkedMap(thread, linkedMap);
|
||||
// add data into set from iterable
|
||||
// 5.If iterable is not present, let iterable be undefined.
|
||||
|
||||
@@ -213,7 +213,7 @@ JSTaggedValue BuiltinsNumber::ToExponential(EcmaRuntimeCallInfo *argv)
|
||||
BUILTINS_API_TRACE(argv->GetThread(), Number, ToExponential);
|
||||
JSThread *thread = argv->GetThread();
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
// 1. Let x be thisNumberValue(this value).
|
||||
// 1. Let x be ? thisNumberValue(this value).
|
||||
JSTaggedNumber value = ThisNumberValue(argv);
|
||||
// 2. ReturnIfAbrupt(x).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
@@ -261,7 +261,7 @@ JSTaggedValue BuiltinsNumber::ToFixed(EcmaRuntimeCallInfo *argv)
|
||||
BUILTINS_API_TRACE(argv->GetThread(), Number, ToFixed);
|
||||
JSThread *thread = argv->GetThread();
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
// 1. Let x be thisNumberValue(this value).
|
||||
// 1. Let x be ? thisNumberValue(this value).
|
||||
JSTaggedNumber value = ThisNumberValue(argv);
|
||||
// 2. ReturnIfAbrupt(x).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
@@ -301,13 +301,14 @@ JSTaggedValue BuiltinsNumber::ToLocaleString(EcmaRuntimeCallInfo *argv)
|
||||
JSThread *thread = argv->GetThread();
|
||||
BUILTINS_API_TRACE(thread, Number, ToLocaleString);
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
// 1. Let x be thisNumberValue(this value).
|
||||
// 1. Let x be ? thisNumberValue(this value).
|
||||
JSTaggedNumber x = ThisNumberValue(argv);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// 2. Let numberFormat be ? Construct(%NumberFormat%, « locales, options »).
|
||||
JSHandle<JSTaggedValue> func = thread->GetEcmaVM()->GetGlobalEnv()->GetNumberFormatFunction();
|
||||
JSHandle<JSTaggedValue> ctor = thread->GetEcmaVM()->GetGlobalEnv()->GetNumberFormatFunction();
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSNumberFormat> numberFormat =
|
||||
JSHandle<JSNumberFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(func), func));
|
||||
JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor);
|
||||
JSHandle<JSNumberFormat> numberFormat = JSHandle<JSNumberFormat>::Cast(obj);
|
||||
JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0);
|
||||
JSHandle<JSTaggedValue> options = GetCallArg(argv, 1);
|
||||
JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, options);
|
||||
@@ -326,7 +327,7 @@ JSTaggedValue BuiltinsNumber::ToPrecision(EcmaRuntimeCallInfo *argv)
|
||||
BUILTINS_API_TRACE(argv->GetThread(), Number, ToPrecision);
|
||||
JSThread *thread = argv->GetThread();
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
// 1. Let x be thisNumberValue(this value).
|
||||
// 1. Let x be ? thisNumberValue(this value).
|
||||
JSTaggedNumber value = ThisNumberValue(argv);
|
||||
// 2. ReturnIfAbrupt(x).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
@@ -370,7 +371,7 @@ JSTaggedValue BuiltinsNumber::ToString(EcmaRuntimeCallInfo *argv)
|
||||
BUILTINS_API_TRACE(argv->GetThread(), Number, ToString);
|
||||
JSThread *thread = argv->GetThread();
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
// 1. Let x be thisNumberValue(this value).
|
||||
// 1. Let x be ? thisNumberValue(this value).
|
||||
JSTaggedNumber value = ThisNumberValue(argv);
|
||||
// 2. ReturnIfAbrupt(x).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
@@ -417,8 +418,11 @@ JSTaggedValue BuiltinsNumber::ValueOf(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
ASSERT(argv);
|
||||
BUILTINS_API_TRACE(argv->GetThread(), Number, ValueOf);
|
||||
// 1. Let x be thisNumberValue(this value).
|
||||
return ThisNumberValue(argv);
|
||||
// 1. Let x be ? thisNumberValue(this value).
|
||||
JSTaggedValue x = ThisNumberValue(argv);
|
||||
JSThread *thread = argv->GetThread();
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return x;
|
||||
}
|
||||
|
||||
JSTaggedNumber BuiltinsNumber::ThisNumberValue(EcmaRuntimeCallInfo *argv)
|
||||
|
||||
@@ -419,10 +419,16 @@ JSTaggedValue BuiltinsPromise::PerformPromiseThen(JSThread *thread, const JSHand
|
||||
JSHandle<TaggedArray> argv = factory->NewTaggedArray(2); // 2: 2 means two args stored in array
|
||||
argv->Set(thread, 0, rejectReaction.GetTaggedValue());
|
||||
argv->Set(thread, 1, promise->GetPromiseResult());
|
||||
|
||||
// When a handler is added to a rejected promise for the first time, it is called with its operation
|
||||
// argument set to "handle".
|
||||
if (!promise->GetPromiseIsHandled().ToBoolean()) {
|
||||
JSHandle<JSTaggedValue> reason(thread, JSTaggedValue::Null());
|
||||
thread->GetEcmaVM()->PromiseRejectionTracker(promise, reason, ecmascript::PromiseRejectionEvent::HANDLE);
|
||||
}
|
||||
JSHandle<JSFunction> promiseReactionsJob(env->GetPromiseReactionJob());
|
||||
job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, argv);
|
||||
}
|
||||
promise->SetPromiseIsHandled(thread, JSTaggedValue::True());
|
||||
return capability->GetPromise();
|
||||
}
|
||||
|
||||
|
||||
@@ -66,9 +66,8 @@ JSTaggedValue BuiltinsRegExp::RegExpConstructor(EcmaRuntimeCallInfo *argv)
|
||||
// 4.b If patternIsRegExp is true and flags is undefined
|
||||
if (patternIsRegExp && flags->IsUndefined()) {
|
||||
// 4.b.i Let patternConstructor be Get(pattern, "constructor").
|
||||
JSTaggedValue patternConstructor =
|
||||
FastRuntimeStub::FastGetPropertyByName(thread, pattern.GetTaggedValue(),
|
||||
constructorString.GetTaggedValue());
|
||||
JSTaggedValue patternConstructor = FastRuntimeStub::FastGetPropertyByName(
|
||||
thread, pattern.GetTaggedValue(), constructorString.GetTaggedValue());
|
||||
// 4.b.ii ReturnIfAbrupt(patternConstructor).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// 4.b.iii If SameValue(newTarget, patternConstructor) is true, return pattern.
|
||||
@@ -251,8 +250,7 @@ JSTaggedValue BuiltinsRegExp::GetFlags(EcmaRuntimeCallInfo *argv)
|
||||
// 3. Let result be the empty String.
|
||||
// 4. ~ 19.
|
||||
ASSERT(JSHandle<JSObject>::Cast(thisObj)->IsJSRegExp());
|
||||
uint8_t flagsBits = static_cast<uint8_t>(
|
||||
JSRegExp::Cast(thisObj->GetTaggedObject())->GetOriginalFlags().GetInt());
|
||||
uint8_t flagsBits = static_cast<uint8_t>(JSRegExp::Cast(thisObj->GetTaggedObject())->GetOriginalFlags().GetInt());
|
||||
return FlagsBitsToString(thread, flagsBits);
|
||||
}
|
||||
|
||||
@@ -384,8 +382,8 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
|
||||
// 5. Let global be ToBoolean(Get(rx, "global")).
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
JSHandle<JSTaggedValue> global = globalConst->GetHandledGlobalString();
|
||||
JSTaggedValue globalValue = FastRuntimeStub::FastGetPropertyByName(thread, thisObj.GetTaggedValue(),
|
||||
global.GetTaggedValue());
|
||||
JSTaggedValue globalValue =
|
||||
FastRuntimeStub::FastGetPropertyByName(thread, thisObj.GetTaggedValue(), global.GetTaggedValue());
|
||||
// 6. ReturnIfAbrupt(global).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
bool isGlobal = globalValue.ToBoolean();
|
||||
@@ -396,12 +394,15 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
|
||||
return JSTaggedValue(result);
|
||||
}
|
||||
JSHandle<JSRegExp> regexpObj(thisObj);
|
||||
JSHandle<JSTaggedValue> pattern(thread, regexpObj->GetOriginalSource());
|
||||
JSHandle<JSTaggedValue> flags(thread, regexpObj->GetOriginalFlags());
|
||||
JSMutableHandle<JSTaggedValue> pattern(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> flags(thread, JSTaggedValue::Undefined());
|
||||
if (thisObj->IsJSRegExp()) {
|
||||
pattern.Update(regexpObj->GetOriginalSource());
|
||||
flags.Update(regexpObj->GetOriginalFlags());
|
||||
}
|
||||
if (isCached) {
|
||||
JSTaggedValue cacheResult =
|
||||
cacheTable->FindCachedResult(thread, pattern, flags, inputString,
|
||||
RegExpExecResultCache::MATCH_TYPE, thisObj);
|
||||
JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, inputString,
|
||||
RegExpExecResultCache::MATCH_TYPE, thisObj);
|
||||
if (cacheResult != JSTaggedValue::Undefined()) {
|
||||
return cacheResult;
|
||||
}
|
||||
@@ -409,8 +410,8 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
|
||||
// 8. Else global is true
|
||||
// a. Let fullUnicode be ToBoolean(Get(rx, "unicode")).
|
||||
JSHandle<JSTaggedValue> unicode = globalConst->GetHandledUnicodeString();
|
||||
JSTaggedValue uincodeValue = FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(),
|
||||
unicode.GetTaggedValue());
|
||||
JSTaggedValue uincodeValue =
|
||||
FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(), unicode.GetTaggedValue());
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
bool fullUnicode = uincodeValue.ToBoolean();
|
||||
// b. ReturnIfAbrupt(fullUnicode)
|
||||
@@ -441,8 +442,9 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
|
||||
return JSTaggedValue::Null();
|
||||
}
|
||||
if (isCached) {
|
||||
cacheTable->AddResultInCache(thread, pattern, flags, inputString, array.GetTaggedValue(),
|
||||
RegExpExecResultCache::MATCH_TYPE, 0);
|
||||
RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputString,
|
||||
JSHandle<JSTaggedValue>(array),
|
||||
RegExpExecResultCache::MATCH_TYPE, 0);
|
||||
}
|
||||
// 2. Else, return A.
|
||||
return array.GetTaggedValue();
|
||||
@@ -462,8 +464,8 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv)
|
||||
if (JSTaggedValue::ToString(thread, matchValue)->GetLength() == 0) {
|
||||
// a. Let thisIndex be ToLength(Get(rx, "lastIndex")).
|
||||
JSHandle<JSTaggedValue> lastIndexHandle(
|
||||
thread, FastRuntimeStub::FastGetProperty(
|
||||
thread, thisObj.GetTaggedValue(), lastIndexString.GetTaggedValue()));
|
||||
thread,
|
||||
FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(), lastIndexString.GetTaggedValue()));
|
||||
JSTaggedNumber thisIndex = JSTaggedValue::ToLength(thread, lastIndexHandle);
|
||||
// b. ReturnIfAbrupt(thisIndex).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
@@ -510,8 +512,12 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
|
||||
}
|
||||
|
||||
JSHandle<JSTaggedValue> tagInputString = JSHandle<JSTaggedValue>::Cast(inputString);
|
||||
JSHandle<JSTaggedValue> pattern(thread, regexpHandle->GetOriginalSource());
|
||||
JSHandle<JSTaggedValue> flagsBits(thread, regexpHandle->GetOriginalFlags());
|
||||
JSMutableHandle<JSTaggedValue> pattern(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> flagsBits(thread, JSTaggedValue::Undefined());
|
||||
if (regexp->IsJSRegExp()) {
|
||||
pattern.Update(regexpHandle->GetOriginalSource());
|
||||
flagsBits.Update(regexpHandle->GetOriginalFlags());
|
||||
}
|
||||
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
|
||||
uint32_t length = inputString->GetLength();
|
||||
uint32_t largeStrCount = cacheTable->GetLargeStrCount();
|
||||
@@ -526,9 +532,8 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
|
||||
isCached = true;
|
||||
}
|
||||
if (isCached) {
|
||||
JSTaggedValue cacheResult =
|
||||
cacheTable->FindCachedResult(thread, pattern, flagsBits, tagInputString,
|
||||
RegExpExecResultCache::REPLACE_TYPE, regexp);
|
||||
JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flagsBits, tagInputString,
|
||||
RegExpExecResultCache::REPLACE_TYPE, regexp);
|
||||
if (cacheResult != JSTaggedValue::Undefined()) {
|
||||
return cacheResult;
|
||||
}
|
||||
@@ -591,12 +596,13 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle<JSTag
|
||||
lastIndex = endIndex;
|
||||
}
|
||||
resultString += base::StringHelper::SubString(thread, inputString, nextPosition, inputLength - nextPosition);
|
||||
JSTaggedValue resultValue = factory->NewFromStdString(resultString).GetTaggedValue();
|
||||
auto resultValue = factory->NewFromStdString(resultString);
|
||||
if (isCached) {
|
||||
cacheTable->AddResultInCache(thread, pattern, flagsBits, tagInputString, resultValue,
|
||||
RegExpExecResultCache::REPLACE_TYPE, lastIndex);
|
||||
RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, tagInputString,
|
||||
JSHandle<JSTaggedValue>(resultValue),
|
||||
RegExpExecResultCache::REPLACE_TYPE, lastIndex);
|
||||
}
|
||||
return resultValue;
|
||||
return resultValue.GetTaggedValue();
|
||||
}
|
||||
|
||||
// 21.2.5.8
|
||||
@@ -635,8 +641,8 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
|
||||
// 8. Let global be ToBoolean(Get(rx, "global")).
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSTaggedValue> global = globalConst->GetHandledGlobalString();
|
||||
JSTaggedValue globalValue = FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(),
|
||||
global.GetTaggedValue());
|
||||
JSTaggedValue globalValue =
|
||||
FastRuntimeStub::FastGetProperty(thread, thisObj.GetTaggedValue(), global.GetTaggedValue());
|
||||
// 9. ReturnIfAbrupt(global).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
bool isGlobal = globalValue.ToBoolean();
|
||||
@@ -652,8 +658,8 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
|
||||
// b. ReturnIfAbrupt(fullUnicode).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// c. Let setStatus be Set(rx, "lastIndex", 0, true).
|
||||
FastRuntimeStub::FastSetProperty(
|
||||
thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue(), JSTaggedValue(0), true);
|
||||
FastRuntimeStub::FastSetProperty(thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue(), JSTaggedValue(0),
|
||||
true);
|
||||
// d. ReturnIfAbrupt(setStatus).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
@@ -713,8 +719,8 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv)
|
||||
uint32_t nextIndex = AdvanceStringIndex(thread, inputStr, thisIndex, fullUnicode);
|
||||
nextIndexHandle.Update(JSTaggedValue(nextIndex));
|
||||
// d. Let setStatus be Set(rx, "lastIndex", nextIndex, true).
|
||||
FastRuntimeStub::FastSetProperty(
|
||||
thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue(), nextIndexHandle.GetTaggedValue(), true);
|
||||
FastRuntimeStub::FastSetProperty(thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue(),
|
||||
nextIndexHandle.GetTaggedValue(), true);
|
||||
// e. ReturnIfAbrupt(setStatus).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
@@ -968,13 +974,16 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
|
||||
}
|
||||
|
||||
JSHandle<JSRegExp> regexpHandle(thisObj);
|
||||
JSHandle<JSTaggedValue> pattern(thread, regexpHandle->GetOriginalSource());
|
||||
JSHandle<JSTaggedValue> flagsBits(thread, regexpHandle->GetOriginalFlags());
|
||||
JSMutableHandle<JSTaggedValue> pattern(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> flagsBits(thread, JSTaggedValue::Undefined());
|
||||
if (thisObj->IsJSRegExp()) {
|
||||
pattern.Update(regexpHandle->GetOriginalSource());
|
||||
flagsBits.Update(regexpHandle->GetOriginalFlags());
|
||||
}
|
||||
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
|
||||
if (isCached) {
|
||||
JSTaggedValue cacheResult =
|
||||
cacheTable->FindCachedResult(thread, pattern, flagsBits, inputString,
|
||||
RegExpExecResultCache::SPLIT_TYPE, thisObj);
|
||||
JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flagsBits, inputString,
|
||||
RegExpExecResultCache::SPLIT_TYPE, thisObj);
|
||||
if (cacheResult != JSTaggedValue::Undefined()) {
|
||||
return cacheResult;
|
||||
}
|
||||
@@ -1064,8 +1073,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
|
||||
// 5. If lengthA = lim, return A.
|
||||
if (aLength == lim) {
|
||||
if (isCached) {
|
||||
cacheTable->AddResultInCache(thread, pattern, flagsBits, inputString, array.GetTaggedValue(),
|
||||
RegExpExecResultCache::SPLIT_TYPE, lastIndex);
|
||||
RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, inputString,
|
||||
JSHandle<JSTaggedValue>(array),
|
||||
RegExpExecResultCache::SPLIT_TYPE, lastIndex);
|
||||
}
|
||||
return array.GetTaggedValue();
|
||||
}
|
||||
@@ -1098,9 +1108,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
|
||||
// f. If lengthA = lim, return A.
|
||||
if (aLength == lim) {
|
||||
if (isCached) {
|
||||
cacheTable->AddResultInCache(thread, pattern, flagsBits, inputString,
|
||||
array.GetTaggedValue(),
|
||||
RegExpExecResultCache::SPLIT_TYPE, lastIndex);
|
||||
RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, inputString,
|
||||
JSHandle<JSTaggedValue>(array),
|
||||
RegExpExecResultCache::SPLIT_TYPE, lastIndex);
|
||||
}
|
||||
return array.GetTaggedValue();
|
||||
}
|
||||
@@ -1119,8 +1129,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv)
|
||||
JSHandle<JSTaggedValue> tValue(factory->NewFromStdString(stdStrT));
|
||||
JSObject::CreateDataProperty(thread, array, aLength, tValue);
|
||||
if (lim == MAX_SPLIT_LIMIT) {
|
||||
cacheTable->AddResultInCache(thread, pattern, flagsBits, inputString, array.GetTaggedValue(),
|
||||
RegExpExecResultCache::SPLIT_TYPE, endIndex);
|
||||
RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, inputString,
|
||||
JSHandle<JSTaggedValue>(array), RegExpExecResultCache::SPLIT_TYPE,
|
||||
endIndex);
|
||||
}
|
||||
// 28. Return A.
|
||||
return array.GetTaggedValue();
|
||||
@@ -1180,8 +1191,7 @@ uint32_t BuiltinsRegExp::AdvanceStringIndex(JSThread *thread, const JSHandle<JST
|
||||
return index + 2;
|
||||
}
|
||||
|
||||
bool BuiltinsRegExp::GetFlagsInternal(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
|
||||
const uint8_t mask)
|
||||
bool BuiltinsRegExp::GetFlagsInternal(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const uint8_t mask)
|
||||
{
|
||||
// 1. Let R be the this value.
|
||||
// 2. If Type(R) is not Object, throw a TypeError exception.
|
||||
@@ -1213,8 +1223,8 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
JSHandle<JSTaggedValue> lastIndexHandle = globalConst->GetHandledLastIndexString();
|
||||
JSTaggedValue result = FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(),
|
||||
lastIndexHandle.GetTaggedValue());
|
||||
JSTaggedValue result =
|
||||
FastRuntimeStub::FastGetProperty(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue());
|
||||
int32_t lastIndex = 0;
|
||||
if (result.IsInt()) {
|
||||
lastIndex = result.GetInt();
|
||||
@@ -1236,13 +1246,16 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
lastIndex = 0;
|
||||
}
|
||||
JSHandle<JSRegExp> regexpObj(regexp);
|
||||
JSHandle<JSTaggedValue> pattern(thread, regexpObj->GetOriginalSource());
|
||||
JSHandle<JSTaggedValue> flags(thread, regexpObj->GetOriginalFlags());
|
||||
JSMutableHandle<JSTaggedValue> pattern(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> flags(thread, JSTaggedValue::Undefined());
|
||||
if (regexp->IsJSRegExp()) {
|
||||
pattern.Update(regexpObj->GetOriginalSource());
|
||||
flags.Update(regexpObj->GetOriginalFlags());
|
||||
}
|
||||
JSHandle<RegExpExecResultCache> cacheTable(thread->GetEcmaVM()->GetRegExpCache());
|
||||
if (lastIndex == 0 && isCached) {
|
||||
JSTaggedValue cacheResult =
|
||||
cacheTable->FindCachedResult(thread, pattern, flags, inputStr,
|
||||
RegExpExecResultCache::EXEC_TYPE, regexp);
|
||||
cacheTable->FindCachedResult(thread, pattern, flags, inputStr, RegExpExecResultCache::EXEC_TYPE, regexp);
|
||||
if (cacheResult != JSTaggedValue::Undefined()) {
|
||||
return cacheResult;
|
||||
}
|
||||
@@ -1253,8 +1266,8 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
JSHandle<EcmaString> uString(globalConst->GetHandledUString());
|
||||
[[maybe_unused]] bool fullUnicode = base::StringHelper::Contains(*flagsStr, *uString);
|
||||
if (lastIndex > length) {
|
||||
FastRuntimeStub::FastSetPropertyByValue(
|
||||
thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), JSTaggedValue(0));
|
||||
FastRuntimeStub::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(),
|
||||
JSTaggedValue(0));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return JSTaggedValue::Null();
|
||||
}
|
||||
@@ -1286,8 +1299,8 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
uint32_t endIndex = matchResult.endIndex_;
|
||||
if (global || sticky) {
|
||||
// a. Let setStatus be Set(R, "lastIndex", e, true).
|
||||
FastRuntimeStub::FastSetPropertyByValue(
|
||||
thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), JSTaggedValue(endIndex));
|
||||
FastRuntimeStub::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(),
|
||||
JSTaggedValue(endIndex));
|
||||
// b. ReturnIfAbrupt(setStatus).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
@@ -1319,8 +1332,9 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle
|
||||
JSObject::CreateDataProperty(thread, results, i, iValue);
|
||||
}
|
||||
if (lastIndex == 0 && isCached) {
|
||||
cacheTable->AddResultInCache(thread, pattern, flags, inputStr, results.GetTaggedValue(),
|
||||
RegExpExecResultCache::EXEC_TYPE, endIndex);
|
||||
RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputStr,
|
||||
JSHandle<JSTaggedValue>(results), RegExpExecResultCache::EXEC_TYPE,
|
||||
endIndex);
|
||||
}
|
||||
// 29. Return A.
|
||||
return results.GetTaggedValue();
|
||||
@@ -1433,9 +1447,9 @@ uint32_t BuiltinsRegExp::UpdateExpressionFlags(JSThread *thread, const CString &
|
||||
|
||||
JSTaggedValue BuiltinsRegExp::FlagsBitsToString(JSThread *thread, uint8_t flags)
|
||||
{
|
||||
ASSERT((flags & 0xC0) == 0); // 0xC0: first 2 bits of flags must be 0
|
||||
ASSERT((flags & 0xC0) == 0); // 0xC0: first 2 bits of flags must be 0
|
||||
|
||||
uint8_t *flagsStr = new uint8_t[7]; // 7: maximum 6 flags + '\0'
|
||||
uint8_t *flagsStr = new uint8_t[7]; // 7: maximum 6 flags + '\0'
|
||||
size_t flagsLen = 0;
|
||||
if (flags & RegExpParser::FLAG_GLOBAL) {
|
||||
flagsStr[flagsLen] = 'g';
|
||||
@@ -1583,15 +1597,16 @@ EcmaString *BuiltinsRegExp::EscapeRegExpPattern(JSThread *thread, const JSHandle
|
||||
|
||||
JSTaggedValue RegExpExecResultCache::CreateCacheTable(JSThread *thread)
|
||||
{
|
||||
int length = CACHE_TABLE_HEADER_SIZE + DEFAULT_CACHE_NUMBER * ENTRY_SIZE;
|
||||
int length = CACHE_TABLE_HEADER_SIZE + INITIAL_CACHE_NUMBER * ENTRY_SIZE;
|
||||
|
||||
auto table = static_cast<RegExpExecResultCache *>(*thread->GetEcmaVM()->GetFactory()->NewDictionaryArray(length));
|
||||
auto table = static_cast<RegExpExecResultCache *>(
|
||||
*thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length, JSTaggedValue::Undefined()));
|
||||
table->SetLargeStrCount(thread, DEFAULT_LARGE_STRING_COUNT);
|
||||
table->SetConflictCount(thread, DEFAULT_CONFLICT_COUNT);
|
||||
table->SetStrLenThreshold(thread, 0);
|
||||
table->SetHitCount(thread, 0);
|
||||
table->SetCacheCount(thread, 0);
|
||||
|
||||
table->SetCacheLength(thread, INITIAL_CACHE_NUMBER);
|
||||
return JSTaggedValue(table);
|
||||
}
|
||||
|
||||
@@ -1609,9 +1624,9 @@ JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, const JS
|
||||
}
|
||||
|
||||
uint32_t hash = pattern->GetKeyHashCode() + flags->GetInt() + input->GetKeyHashCode();
|
||||
uint32_t entry = hash & (RegExpExecResultCache::DEFAULT_CACHE_NUMBER - 1);
|
||||
uint32_t entry = hash & (GetCacheLength() - 1);
|
||||
if (!Match(entry, patternValue, flagsValue, inputValue)) {
|
||||
uint32_t entry2 = (entry + 1) & (DEFAULT_CACHE_NUMBER - 1);
|
||||
uint32_t entry2 = (entry + 1) & (GetCacheLength() - 1);
|
||||
if (!Match(entry2, patternValue, flagsValue, inputValue)) {
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
@@ -1643,9 +1658,11 @@ JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, const JS
|
||||
return result;
|
||||
}
|
||||
|
||||
void RegExpExecResultCache::AddResultInCache(JSThread *thread, const JSHandle<JSTaggedValue> &pattern,
|
||||
void RegExpExecResultCache::AddResultInCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache,
|
||||
const JSHandle<JSTaggedValue> &pattern,
|
||||
const JSHandle<JSTaggedValue> &flags, const JSHandle<JSTaggedValue> &input,
|
||||
JSTaggedValue resultArray, CacheType type, uint32_t lastIndex)
|
||||
const JSHandle<JSTaggedValue> &resultArray, CacheType type,
|
||||
uint32_t lastIndex)
|
||||
{
|
||||
if (!pattern->IsString() || !flags->IsInt() || !input->IsString()) {
|
||||
return;
|
||||
@@ -1657,33 +1674,52 @@ void RegExpExecResultCache::AddResultInCache(JSThread *thread, const JSHandle<JS
|
||||
JSTaggedValue lastIndexValue(lastIndex);
|
||||
|
||||
uint32_t hash = pattern->GetKeyHashCode() + flags->GetInt() + input->GetKeyHashCode();
|
||||
uint32_t entry = hash & (DEFAULT_CACHE_NUMBER - 1);
|
||||
uint32_t entry = hash & (cache->GetCacheLength() - 1);
|
||||
uint32_t index = CACHE_TABLE_HEADER_SIZE + entry * ENTRY_SIZE;
|
||||
if (Get(index) == JSTaggedValue::Undefined()) {
|
||||
SetCacheCount(thread, GetCacheCount() + 1);
|
||||
SetEntry(thread, entry, patternValue, flagsValue, inputValue, lastIndexValue);
|
||||
UpdateResultArray(thread, entry, resultArray, type);
|
||||
} else if (Match(entry, patternValue, flagsValue, inputValue)) {
|
||||
UpdateResultArray(thread, entry, resultArray, type);
|
||||
if (cache->Get(index) == JSTaggedValue::Undefined()) {
|
||||
cache->SetCacheCount(thread, cache->GetCacheCount() + 1);
|
||||
cache->SetEntry(thread, entry, patternValue, flagsValue, inputValue, lastIndexValue);
|
||||
cache->UpdateResultArray(thread, entry, resultArray.GetTaggedValue(), type);
|
||||
} else if (cache->Match(entry, patternValue, flagsValue, inputValue)) {
|
||||
cache->UpdateResultArray(thread, entry, resultArray.GetTaggedValue(), type);
|
||||
} else {
|
||||
uint32_t entry2 = (entry + 1) & (DEFAULT_CACHE_NUMBER - 1);
|
||||
uint32_t entry2 = (entry + 1) & (cache->GetCacheLength() - 1);
|
||||
uint32_t index2 = CACHE_TABLE_HEADER_SIZE + entry2 * ENTRY_SIZE;
|
||||
if (Get(index2) == JSTaggedValue::Undefined()) {
|
||||
SetCacheCount(thread, GetCacheCount() + 1);
|
||||
SetEntry(thread, entry2, patternValue, flagsValue, inputValue, lastIndexValue);
|
||||
UpdateResultArray(thread, entry2, resultArray, type);
|
||||
} else if (Match(entry2, patternValue, flagsValue, inputValue)) {
|
||||
UpdateResultArray(thread, entry2, resultArray, type);
|
||||
if (cache->GetCacheLength() < DEFAULT_CACHE_NUMBER) {
|
||||
GrowRegexpCache(thread, cache);
|
||||
// update value after gc.
|
||||
patternValue = pattern.GetTaggedValue();
|
||||
flagsValue = flags.GetTaggedValue();
|
||||
inputValue = input.GetTaggedValue();
|
||||
|
||||
cache->SetCacheLength(thread, DEFAULT_CACHE_NUMBER);
|
||||
entry2 = hash & (cache->GetCacheLength() - 1);
|
||||
index2 = CACHE_TABLE_HEADER_SIZE + entry2 * ENTRY_SIZE;
|
||||
}
|
||||
if (cache->Get(index2) == JSTaggedValue::Undefined()) {
|
||||
cache->SetCacheCount(thread, cache->GetCacheCount() + 1);
|
||||
cache->SetEntry(thread, entry2, patternValue, flagsValue, inputValue, lastIndexValue);
|
||||
cache->UpdateResultArray(thread, entry2, resultArray.GetTaggedValue(), type);
|
||||
} else if (cache->Match(entry2, patternValue, flagsValue, inputValue)) {
|
||||
cache->UpdateResultArray(thread, entry2, resultArray.GetTaggedValue(), type);
|
||||
} else {
|
||||
SetConflictCount(thread, GetConflictCount() - 1);
|
||||
SetCacheCount(thread, GetCacheCount() - 1);
|
||||
ClearEntry(thread, entry2);
|
||||
SetEntry(thread, entry, patternValue, flagsValue, inputValue, lastIndexValue);
|
||||
UpdateResultArray(thread, entry, resultArray, type);
|
||||
cache->SetConflictCount(thread, cache->GetConflictCount() > 1 ? (cache->GetConflictCount() - 1) : 0);
|
||||
cache->SetCacheCount(thread, cache->GetCacheCount() - 1);
|
||||
cache->ClearEntry(thread, entry2);
|
||||
cache->SetEntry(thread, entry, patternValue, flagsValue, inputValue, lastIndexValue);
|
||||
cache->UpdateResultArray(thread, entry, resultArray.GetTaggedValue(), type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegExpExecResultCache::GrowRegexpCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache)
|
||||
{
|
||||
int length = CACHE_TABLE_HEADER_SIZE + DEFAULT_CACHE_NUMBER * ENTRY_SIZE;
|
||||
auto factory = thread->GetEcmaVM()->GetFactory();
|
||||
auto newCache = factory->ExtendArray(JSHandle<TaggedArray>(cache), length, JSTaggedValue::Undefined());
|
||||
thread->GetEcmaVM()->SetRegExpCache(newCache.GetTaggedValue());
|
||||
}
|
||||
|
||||
void RegExpExecResultCache::SetEntry(JSThread *thread, int entry, JSTaggedValue &pattern, JSTaggedValue &flags,
|
||||
JSTaggedValue &input, JSTaggedValue &lastIndexValue)
|
||||
{
|
||||
|
||||
@@ -115,9 +115,12 @@ public:
|
||||
JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle<JSTaggedValue> &patten,
|
||||
const JSHandle<JSTaggedValue> &flags, const JSHandle<JSTaggedValue> &input,
|
||||
CacheType type, const JSHandle<JSTaggedValue> ®exp);
|
||||
void AddResultInCache(JSThread *thread, const JSHandle<JSTaggedValue> &patten, const JSHandle<JSTaggedValue> &flags,
|
||||
const JSHandle<JSTaggedValue> &input, JSTaggedValue resultArray, CacheType type,
|
||||
uint32_t lastIndex);
|
||||
static void AddResultInCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache,
|
||||
const JSHandle<JSTaggedValue> &patten, const JSHandle<JSTaggedValue> &flags,
|
||||
const JSHandle<JSTaggedValue> &input, const JSHandle<JSTaggedValue> &resultArray,
|
||||
CacheType type, uint32_t lastIndex);
|
||||
|
||||
static void GrowRegexpCache(JSThread *thread, JSHandle<RegExpExecResultCache> cache);
|
||||
|
||||
void ClearEntry(JSThread *thread, int entry);
|
||||
void SetEntry(JSThread *thread, int entry, JSTaggedValue &patten, JSTaggedValue &flags, JSTaggedValue &input,
|
||||
@@ -180,16 +183,28 @@ public:
|
||||
return Get(STRING_LENGTH_THRESHOLD_INDEX).GetInt();
|
||||
}
|
||||
|
||||
inline void SetCacheLength(JSThread *thread, int length)
|
||||
{
|
||||
Set(thread, CACHE_LENGTH_INDEX, JSTaggedValue(length));
|
||||
}
|
||||
|
||||
inline int GetCacheLength()
|
||||
{
|
||||
return Get(CACHE_LENGTH_INDEX).GetInt();
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int DEFAULT_LARGE_STRING_COUNT = 10;
|
||||
static constexpr int DEFAULT_CONFLICT_COUNT = 100;
|
||||
static constexpr int INITIAL_CACHE_NUMBER = 0x10;
|
||||
static constexpr int DEFAULT_CACHE_NUMBER = 0x1000;
|
||||
static constexpr int CACHE_COUNT_INDEX = 0;
|
||||
static constexpr int CACHE_HIT_COUNT_INDEX = 1;
|
||||
static constexpr int LARGE_STRING_COUNT_INDEX = 2;
|
||||
static constexpr int CONFLICT_COUNT_INDEX = 3;
|
||||
static constexpr int STRING_LENGTH_THRESHOLD_INDEX = 4;
|
||||
static constexpr int CACHE_TABLE_HEADER_SIZE = 5;
|
||||
static constexpr int CACHE_LENGTH_INDEX = 5;
|
||||
static constexpr int CACHE_TABLE_HEADER_SIZE = 6;
|
||||
static constexpr int PATTERN_INDEX = 0;
|
||||
static constexpr int FLAG_INDEX = 1;
|
||||
static constexpr int INPUT_STRING_INDEX = 2;
|
||||
|
||||
@@ -46,7 +46,7 @@ JSTaggedValue BuiltinsSet::SetConstructor(EcmaRuntimeCallInfo *argv)
|
||||
JSHandle<JSSet> set = JSHandle<JSSet>::Cast(obj);
|
||||
// 3.ReturnIfAbrupt(set).
|
||||
// 4.Set set’s [[SetData]] internal slot to a new empty List.
|
||||
JSTaggedValue linkedSet = LinkedHashSet::Create(thread);
|
||||
JSHandle<LinkedHashSet> linkedSet = LinkedHashSet::Create(thread);
|
||||
set->SetLinkedSet(thread, linkedSet);
|
||||
|
||||
// add data into set from iterable
|
||||
@@ -116,7 +116,7 @@ JSTaggedValue BuiltinsSet::Add(EcmaRuntimeCallInfo *argv)
|
||||
}
|
||||
|
||||
JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
|
||||
JSHandle<JSSet> set(thread, JSSet::Cast(*JSTaggedValue::ToObject(thread, self)));
|
||||
JSHandle<JSSet> set(JSTaggedValue::ToObject(thread, self));
|
||||
|
||||
JSSet::Add(thread, set, value);
|
||||
return set.GetTaggedValue();
|
||||
|
||||
@@ -45,7 +45,7 @@ JSTaggedValue BuiltinsWeakMap::WeakMapConstructor(EcmaRuntimeCallInfo *argv)
|
||||
JSHandle<JSWeakMap> weakMap = JSHandle<JSWeakMap>::Cast(obj);
|
||||
|
||||
// 4.Set weakmap’s [[WeakMapData]] internal slot to a new empty List.
|
||||
JSTaggedValue linkedMap = LinkedHashMap::Create(thread);
|
||||
JSHandle<LinkedHashMap> linkedMap = LinkedHashMap::Create(thread);
|
||||
weakMap->SetLinkedMap(thread, linkedMap);
|
||||
// add data into set from iterable
|
||||
// 5.If iterable is not present, let iterable be undefined.
|
||||
|
||||
@@ -45,7 +45,7 @@ JSTaggedValue BuiltinsWeakSet::WeakSetConstructor(EcmaRuntimeCallInfo *argv)
|
||||
JSHandle<JSWeakSet> weakSet = JSHandle<JSWeakSet>::Cast(obj);
|
||||
// 3.ReturnIfAbrupt(weakSet).
|
||||
// 4.WeakSet set’s [[WeakSetData]] internal slot to a new empty List.
|
||||
JSTaggedValue linkedSet = LinkedHashSet::Create(thread);
|
||||
JSHandle<LinkedHashSet> linkedSet = LinkedHashSet::Create(thread);
|
||||
weakSet->SetLinkedSet(thread, linkedSet);
|
||||
|
||||
// add data into weakset from iterable
|
||||
|
||||
@@ -84,7 +84,7 @@ JSFunction *BuiltinsObjectTestCreate(JSThread *thread)
|
||||
JSObject *TestNewJSObject(JSThread *thread, const JSHandle<JSHClass> &dynClass)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSObject *obj = JSObject::Cast(factory->NewDynObject(dynClass, JSObject::MIN_PROPERTIES_LENGTH));
|
||||
JSObject *obj = JSObject::Cast(factory->NewDynObject(dynClass));
|
||||
|
||||
obj->SetElements(thread, factory->EmptyArray().GetTaggedValue(), SKIP_BARRIER);
|
||||
return obj;
|
||||
|
||||
@@ -109,6 +109,7 @@ void PandaFileTranslator::TranslateClasses(const panda_file::File &pf, const CSt
|
||||
InitializeMemory(method, nullptr, &pf, mda.GetMethodId(), codeDataAccessor.GetCodeId(),
|
||||
mda.GetAccessFlags(), codeDataAccessor.GetNumArgs(), nullptr);
|
||||
method->SetHotnessCounter(EcmaInterpreter::METHOD_HOTNESS_THRESHOLD);
|
||||
method->SetCallTypeFromAnnotation();
|
||||
const uint8_t *insns = codeDataAccessor.GetInstructions();
|
||||
if (this->translated_code_.find(insns) == this->translated_code_.end()) {
|
||||
this->translated_code_.insert(insns);
|
||||
@@ -241,13 +242,7 @@ Program *PandaFileTranslator::GenerateProgram(const panda_file::File &pf)
|
||||
array_size_t length = literal->GetLength();
|
||||
|
||||
JSHandle<JSArray> arr(JSArray::ArrayCreate(thread_, JSTaggedNumber(length)));
|
||||
JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> arrValue(thread_, JSTaggedValue::Undefined());
|
||||
for (array_size_t i = 0; i < length; i++) {
|
||||
key.Update(JSTaggedValue(static_cast<int32_t>(i)));
|
||||
arrValue.Update(literal->Get(i));
|
||||
JSObject::DefinePropertyByLiteral(thread_, JSHandle<JSObject>::Cast(arr), key, arrValue);
|
||||
}
|
||||
arr->SetElements(thread_, literal);
|
||||
constpool->Set(thread_, value.GetConstpoolIndex(), arr.GetTaggedValue());
|
||||
} else if (value.GetConstpoolType() == ConstPoolType::CLASS_LITERAL) {
|
||||
size_t index = it.first;
|
||||
@@ -350,6 +345,23 @@ void PandaFileTranslator::UpdateICOffset(JSMethod *method, uint8_t *pc) const
|
||||
case EcmaOpcode::TRYSTGLOBALBYNAME_PREF_ID32:
|
||||
case EcmaOpcode::LDGLOBALVAR_PREF_ID32:
|
||||
case EcmaOpcode::STGLOBALVAR_PREF_ID32:
|
||||
case EcmaOpcode::ADD2DYN_PREF_V8:
|
||||
case EcmaOpcode::SUB2DYN_PREF_V8:
|
||||
case EcmaOpcode::MUL2DYN_PREF_V8:
|
||||
case EcmaOpcode::DIV2DYN_PREF_V8:
|
||||
case EcmaOpcode::MOD2DYN_PREF_V8:
|
||||
case EcmaOpcode::SHL2DYN_PREF_V8:
|
||||
case EcmaOpcode::SHR2DYN_PREF_V8:
|
||||
case EcmaOpcode::ASHR2DYN_PREF_V8:
|
||||
case EcmaOpcode::AND2DYN_PREF_V8:
|
||||
case EcmaOpcode::OR2DYN_PREF_V8:
|
||||
case EcmaOpcode::XOR2DYN_PREF_V8:
|
||||
case EcmaOpcode::EQDYN_PREF_V8:
|
||||
case EcmaOpcode::NOTEQDYN_PREF_V8:
|
||||
case EcmaOpcode::LESSDYN_PREF_V8:
|
||||
case EcmaOpcode::LESSEQDYN_PREF_V8:
|
||||
case EcmaOpcode::GREATERDYN_PREF_V8:
|
||||
case EcmaOpcode::GREATEREQDYN_PREF_V8:
|
||||
method->UpdateSlotSize(1);
|
||||
break;
|
||||
case EcmaOpcode::LDOBJBYVALUE_PREF_V8_V8:
|
||||
|
||||
@@ -44,11 +44,13 @@ source_set("libark_jsoptimizer_static") {
|
||||
"circuit_builder.cpp",
|
||||
"fast_stub.cpp",
|
||||
"gate.cpp",
|
||||
"js_thread_offset_table.cpp",
|
||||
"llvm_codegen.cpp",
|
||||
"llvm_ir_builder.cpp",
|
||||
"scheduler.cpp",
|
||||
"stub.cpp",
|
||||
"stub_descriptor.cpp",
|
||||
"triple.cpp",
|
||||
"type.cpp",
|
||||
"verifier.cpp",
|
||||
]
|
||||
@@ -67,8 +69,6 @@ source_set("libark_jsoptimizer_static") {
|
||||
}
|
||||
|
||||
libs = [
|
||||
"stdc++",
|
||||
"z",
|
||||
"LLVMTarget",
|
||||
"LLVMObject",
|
||||
"LLVMMC",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/compiler/circuit.h"
|
||||
#include "ecmascript/compiler/compiler_macros.h"
|
||||
|
||||
namespace kungfu {
|
||||
Circuit::Circuit() : space({}), circuitSize(0), gateCounter(0), time(1), dataSection({})
|
||||
@@ -56,8 +57,8 @@ Gate *Circuit::AllocateGateSpace(size_t numIns)
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
|
||||
AddrShift Circuit::NewGate(
|
||||
OpCode opcode, BitField bitfield, size_t numIns, const AddrShift inList[], TypeCode type, MarkCode mark)
|
||||
GateRef Circuit::NewGate(
|
||||
OpCode opcode, BitField bitfield, size_t numIns, const GateRef inList[], TypeCode type, MarkCode mark)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (numIns != opcode.GetOpCodeNumIns(bitfield)) {
|
||||
@@ -79,54 +80,56 @@ AddrShift Circuit::NewGate(
|
||||
return this->SaveGatePtr(newGate);
|
||||
}
|
||||
|
||||
AddrShift Circuit::NewGate(
|
||||
OpCode opcode, BitField bitfield, const std::vector<AddrShift> &inList, TypeCode type, MarkCode mark)
|
||||
GateRef Circuit::NewGate(
|
||||
OpCode opcode, BitField bitfield, const std::vector<GateRef> &inList, TypeCode type, MarkCode mark)
|
||||
{
|
||||
return this->NewGate(opcode, bitfield, inList.size(), inList.data(), type, mark);
|
||||
}
|
||||
|
||||
void Circuit::PrintAllGates() const
|
||||
{
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
const auto &gateList = this->GetAllGates();
|
||||
for (auto &gate : gateList) {
|
||||
this->LoadGatePtrConst(gate)->Print();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<AddrShift> Circuit::GetAllGates() const
|
||||
std::vector<GateRef> Circuit::GetAllGates() const
|
||||
{
|
||||
std::vector<AddrShift> gateList;
|
||||
std::vector<GateRef> gateList;
|
||||
gateList.push_back(0);
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
for (size_t out = sizeof(Gate); out < this->circuitSize;
|
||||
out += Gate::GetGateSize(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
reinterpret_cast<const Out *>(this->LoadGatePtrConst(AddrShift(out)))->GetIndex() + 1)) {
|
||||
reinterpret_cast<const Out *>(this->LoadGatePtrConst(GateRef(out)))->GetIndex() + 1)) {
|
||||
gateList.push_back(
|
||||
this->SaveGatePtr(reinterpret_cast<const Out *>(this->LoadGatePtrConst(AddrShift(out)))->GetGateConst()));
|
||||
this->SaveGatePtr(reinterpret_cast<const Out *>(this->LoadGatePtrConst(GateRef(out)))->GetGateConst()));
|
||||
}
|
||||
return gateList;
|
||||
}
|
||||
|
||||
AddrShift Circuit::SaveGatePtr(const Gate *gate) const
|
||||
GateRef Circuit::SaveGatePtr(const Gate *gate) const
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return static_cast<AddrShift>(reinterpret_cast<const uint8_t *>(gate) - this->GetDataPtrConst(0));
|
||||
return static_cast<GateRef>(reinterpret_cast<const uint8_t *>(gate) - this->GetDataPtrConst(0));
|
||||
}
|
||||
|
||||
Gate *Circuit::LoadGatePtr(AddrShift shift)
|
||||
Gate *Circuit::LoadGatePtr(GateRef shift)
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<Gate *>(this->GetDataPtr(shift));
|
||||
}
|
||||
|
||||
const Gate *Circuit::LoadGatePtrConst(AddrShift shift) const
|
||||
const Gate *Circuit::LoadGatePtrConst(GateRef shift) const
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<const Gate *>(this->GetDataPtrConst(shift));
|
||||
}
|
||||
|
||||
AddrShift Circuit::GetCircuitRoot(OpCode opcode)
|
||||
GateRef Circuit::GetCircuitRoot(OpCode opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
case OpCode::CIRCUIT_ROOT:
|
||||
@@ -177,32 +180,27 @@ TimeStamp Circuit::GetTime() const
|
||||
return this->time;
|
||||
}
|
||||
|
||||
MarkCode Circuit::GetMark(AddrShift gate) const
|
||||
MarkCode Circuit::GetMark(GateRef gate) const
|
||||
{
|
||||
return this->LoadGatePtrConst(gate)->GetMark(this->GetTime());
|
||||
}
|
||||
|
||||
TypeCode Circuit::GetTypeCode(AddrShift gate) const
|
||||
{
|
||||
return this->LoadGatePtrConst(gate)->GetTypeCode();
|
||||
}
|
||||
|
||||
void Circuit::SetMark(AddrShift gate, MarkCode mark) const
|
||||
void Circuit::SetMark(GateRef gate, MarkCode mark) const
|
||||
{
|
||||
const_cast<Gate *>(this->LoadGatePtrConst(gate))->SetMark(mark, this->GetTime());
|
||||
}
|
||||
|
||||
bool Circuit::Verify(AddrShift gate) const
|
||||
bool Circuit::Verify(GateRef gate) const
|
||||
{
|
||||
return this->LoadGatePtrConst(gate)->Verify();
|
||||
}
|
||||
|
||||
AddrShift Circuit::NullGate()
|
||||
GateRef Circuit::NullGate()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Circuit::IsLoopHead(AddrShift gate) const
|
||||
bool Circuit::IsLoopHead(GateRef gate) const
|
||||
{
|
||||
if (gate != NullGate()) {
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
@@ -211,7 +209,7 @@ bool Circuit::IsLoopHead(AddrShift gate) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Circuit::IsControlCase(AddrShift gate) const
|
||||
bool Circuit::IsControlCase(GateRef gate) const
|
||||
{
|
||||
if (gate != NullGate()) {
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
@@ -220,7 +218,7 @@ bool Circuit::IsControlCase(AddrShift gate) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Circuit::IsSelector(AddrShift gate) const
|
||||
bool Circuit::IsSelector(GateRef gate) const
|
||||
{
|
||||
if (gate != NullGate()) {
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
@@ -230,9 +228,9 @@ bool Circuit::IsSelector(AddrShift gate) const
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<AddrShift> Circuit::GetInVector(AddrShift gate) const
|
||||
std::vector<GateRef> Circuit::GetInVector(GateRef gate) const
|
||||
{
|
||||
std::vector<AddrShift> result;
|
||||
std::vector<GateRef> result;
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
for (size_t idx = 0; idx < curGate->GetNumIns(); idx++) {
|
||||
result.push_back(this->SaveGatePtr(curGate->GetInGateConst(idx)));
|
||||
@@ -240,27 +238,27 @@ std::vector<AddrShift> Circuit::GetInVector(AddrShift gate) const
|
||||
return result;
|
||||
}
|
||||
|
||||
AddrShift Circuit::GetIn(AddrShift gate, size_t idx) const
|
||||
GateRef Circuit::GetIn(GateRef gate, size_t idx) const
|
||||
{
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
return this->SaveGatePtr(curGate->GetInGateConst(idx));
|
||||
}
|
||||
|
||||
bool Circuit::IsInGateNull(AddrShift gate, size_t idx) const
|
||||
bool Circuit::IsInGateNull(GateRef gate, size_t idx) const
|
||||
{
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
return curGate->GetInConst(idx)->IsGateNull();
|
||||
}
|
||||
|
||||
bool Circuit::IsFirstOutNull(AddrShift gate) const
|
||||
bool Circuit::IsFirstOutNull(GateRef gate) const
|
||||
{
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
return curGate->IsFirstOutNull();
|
||||
}
|
||||
|
||||
std::vector<AddrShift> Circuit::GetOutVector(AddrShift gate) const
|
||||
std::vector<GateRef> Circuit::GetOutVector(GateRef gate) const
|
||||
{
|
||||
std::vector<AddrShift> result;
|
||||
std::vector<GateRef> result;
|
||||
const Gate *curGate = this->LoadGatePtrConst(gate);
|
||||
if (!curGate->IsFirstOutNull()) {
|
||||
const Out *curOut = curGate->GetFirstOutConst();
|
||||
@@ -273,47 +271,57 @@ std::vector<AddrShift> Circuit::GetOutVector(AddrShift gate) const
|
||||
return result;
|
||||
}
|
||||
|
||||
void Circuit::NewIn(AddrShift gate, size_t idx, AddrShift in)
|
||||
void Circuit::NewIn(GateRef gate, size_t idx, GateRef in)
|
||||
{
|
||||
this->LoadGatePtr(gate)->NewIn(idx, this->LoadGatePtr(in));
|
||||
}
|
||||
|
||||
void Circuit::ModifyIn(AddrShift gate, size_t idx, AddrShift in)
|
||||
void Circuit::ModifyIn(GateRef gate, size_t idx, GateRef in)
|
||||
{
|
||||
this->LoadGatePtr(gate)->ModifyIn(idx, this->LoadGatePtr(in));
|
||||
}
|
||||
|
||||
void Circuit::DeleteIn(AddrShift gate, size_t idx)
|
||||
void Circuit::DeleteIn(GateRef gate, size_t idx)
|
||||
{
|
||||
this->LoadGatePtr(gate)->DeleteIn(idx);
|
||||
}
|
||||
|
||||
void Circuit::DeleteGate(AddrShift gate)
|
||||
void Circuit::DeleteGate(GateRef gate)
|
||||
{
|
||||
this->LoadGatePtr(gate)->DeleteGate();
|
||||
}
|
||||
|
||||
void Circuit::SetOpCode(AddrShift gate, OpCode opcode)
|
||||
void Circuit::SetOpCode(GateRef gate, OpCode opcode)
|
||||
{
|
||||
this->LoadGatePtr(gate)->SetOpCode(opcode);
|
||||
}
|
||||
|
||||
OpCode Circuit::GetOpCode(AddrShift gate) const
|
||||
void Circuit::SetTypeCode(GateRef gate, TypeCode type)
|
||||
{
|
||||
this->LoadGatePtr(gate)->SetTypeCode(type);
|
||||
}
|
||||
|
||||
TypeCode Circuit::GetTypeCode(GateRef gate) const
|
||||
{
|
||||
return this->LoadGatePtrConst(gate)->GetTypeCode();
|
||||
}
|
||||
|
||||
OpCode Circuit::GetOpCode(GateRef gate) const
|
||||
{
|
||||
return this->LoadGatePtrConst(gate)->GetOpCode();
|
||||
}
|
||||
|
||||
GateId Circuit::GetId(AddrShift gate) const
|
||||
GateId Circuit::GetId(GateRef gate) const
|
||||
{
|
||||
return this->LoadGatePtrConst(gate)->GetId();
|
||||
}
|
||||
|
||||
BitField Circuit::GetBitField(AddrShift gate) const
|
||||
BitField Circuit::GetBitField(GateRef gate) const
|
||||
{
|
||||
return this->LoadGatePtrConst(gate)->GetBitField();
|
||||
}
|
||||
|
||||
void Circuit::Print(AddrShift gate) const
|
||||
void Circuit::Print(GateRef gate) const
|
||||
{
|
||||
this->LoadGatePtrConst(gate)->Print();
|
||||
}
|
||||
|
||||
@@ -23,10 +23,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "ecmascript/compiler/gate.h"
|
||||
#include "ecmascript/frames.h"
|
||||
#include "libpandabase/macros.h"
|
||||
#include "securec.h"
|
||||
#include "ecmascript/frames.h"
|
||||
|
||||
|
||||
namespace kungfu {
|
||||
const size_t INITIAL_SPACE = 1U << 0U; // this should be tuned
|
||||
@@ -43,41 +42,42 @@ public:
|
||||
Circuit(Circuit &&circuit) = default;
|
||||
Circuit &operator=(Circuit &&circuit) = default;
|
||||
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
|
||||
AddrShift NewGate(OpCode op, BitField bitfield, size_t numIns, const AddrShift inList[], TypeCode type,
|
||||
GateRef NewGate(OpCode op, BitField bitfield, size_t numIns, const GateRef inList[], TypeCode type,
|
||||
MarkCode mark = MarkCode::EMPTY);
|
||||
AddrShift NewGate(OpCode op, BitField bitfield, const std::vector<AddrShift> &inList, TypeCode type,
|
||||
GateRef NewGate(OpCode op, BitField bitfield, const std::vector<GateRef> &inList, TypeCode type,
|
||||
MarkCode mark = MarkCode::EMPTY);
|
||||
void PrintAllGates() const;
|
||||
[[nodiscard]] std::vector<AddrShift> GetAllGates() const;
|
||||
[[nodiscard]] static AddrShift GetCircuitRoot(OpCode opcode);
|
||||
[[nodiscard]] std::vector<GateRef> GetAllGates() const;
|
||||
[[nodiscard]] static GateRef GetCircuitRoot(OpCode opcode);
|
||||
void AdvanceTime() const;
|
||||
void ResetAllGateTimeStamps() const;
|
||||
[[nodiscard]] static AddrShift NullGate();
|
||||
[[nodiscard]] bool IsLoopHead(AddrShift gate) const;
|
||||
[[nodiscard]] bool IsSelector(AddrShift gate) const;
|
||||
[[nodiscard]] bool IsControlCase(AddrShift gate) const;
|
||||
[[nodiscard]] AddrShift GetIn(AddrShift gate, size_t idx) const;
|
||||
[[nodiscard]] bool IsInGateNull(AddrShift gate, size_t idx) const;
|
||||
[[nodiscard]] bool IsFirstOutNull(AddrShift gate) const;
|
||||
[[nodiscard]] std::vector<AddrShift> GetInVector(AddrShift gate) const;
|
||||
[[nodiscard]] std::vector<AddrShift> GetOutVector(AddrShift gate) const;
|
||||
void NewIn(AddrShift gate, size_t idx, AddrShift in);
|
||||
void ModifyIn(AddrShift gate, size_t idx, AddrShift in);
|
||||
void DeleteIn(AddrShift gate, size_t idx);
|
||||
void DeleteGate(AddrShift gate);
|
||||
[[nodiscard]] GateId GetId(AddrShift gate) const;
|
||||
[[nodiscard]] BitField GetBitField(AddrShift gate) const;
|
||||
void Print(AddrShift gate) const;
|
||||
void SetOpCode(AddrShift gate, OpCode opcode);
|
||||
[[nodiscard]] OpCode GetOpCode(AddrShift gate) const;
|
||||
[[nodiscard]] static GateRef NullGate();
|
||||
[[nodiscard]] bool IsLoopHead(GateRef gate) const;
|
||||
[[nodiscard]] bool IsSelector(GateRef gate) const;
|
||||
[[nodiscard]] bool IsControlCase(GateRef gate) const;
|
||||
[[nodiscard]] GateRef GetIn(GateRef gate, size_t idx) const;
|
||||
[[nodiscard]] bool IsInGateNull(GateRef gate, size_t idx) const;
|
||||
[[nodiscard]] bool IsFirstOutNull(GateRef gate) const;
|
||||
[[nodiscard]] std::vector<GateRef> GetInVector(GateRef gate) const;
|
||||
[[nodiscard]] std::vector<GateRef> GetOutVector(GateRef gate) const;
|
||||
void NewIn(GateRef gate, size_t idx, GateRef in);
|
||||
void ModifyIn(GateRef gate, size_t idx, GateRef in);
|
||||
void DeleteIn(GateRef gate, size_t idx);
|
||||
void DeleteGate(GateRef gate);
|
||||
[[nodiscard]] GateId GetId(GateRef gate) const;
|
||||
[[nodiscard]] BitField GetBitField(GateRef gate) const;
|
||||
void Print(GateRef gate) const;
|
||||
void SetOpCode(GateRef gate, OpCode opcode);
|
||||
void SetTypeCode(GateRef gate, TypeCode type);
|
||||
[[nodiscard]] OpCode GetOpCode(GateRef gate) const;
|
||||
[[nodiscard]] TimeStamp GetTime() const;
|
||||
[[nodiscard]] MarkCode GetMark(AddrShift gate) const;
|
||||
[[nodiscard]] TypeCode GetTypeCode(AddrShift gate) const;
|
||||
void SetMark(AddrShift gate, MarkCode mark) const;
|
||||
[[nodiscard]] bool Verify(AddrShift gate) const;
|
||||
[[nodiscard]] Gate *LoadGatePtr(AddrShift shift);
|
||||
[[nodiscard]] const Gate *LoadGatePtrConst(AddrShift shift) const;
|
||||
[[nodiscard]] AddrShift SaveGatePtr(const Gate *gate) const;
|
||||
[[nodiscard]] MarkCode GetMark(GateRef gate) const;
|
||||
[[nodiscard]] TypeCode GetTypeCode(GateRef gate) const;
|
||||
void SetMark(GateRef gate, MarkCode mark) const;
|
||||
[[nodiscard]] bool Verify(GateRef gate) const;
|
||||
[[nodiscard]] Gate *LoadGatePtr(GateRef shift);
|
||||
[[nodiscard]] const Gate *LoadGatePtrConst(GateRef shift) const;
|
||||
[[nodiscard]] GateRef SaveGatePtr(const Gate *gate) const;
|
||||
[[nodiscard]] std::vector<uint8_t> GetDataSection() const;
|
||||
void SetDataSection(const std::vector<uint8_t> &data);
|
||||
[[nodiscard]] size_t GetCircuitDataSize() const;
|
||||
|
||||
@@ -15,203 +15,230 @@
|
||||
|
||||
#include "ecmascript/compiler/circuit_builder.h"
|
||||
#include "include/coretypes/tagged_value.h"
|
||||
#include "triple.h"
|
||||
#include "utils/bit_utils.h"
|
||||
|
||||
namespace kungfu {
|
||||
AddrShift CircuitBuilder::NewArguments(size_t index)
|
||||
using TaggedValue = panda::coretypes::TaggedValue;
|
||||
GateRef CircuitBuilder::NewArguments(size_t index)
|
||||
{
|
||||
auto argListOfCircuit = Circuit::GetCircuitRoot(OpCode(OpCode::ARG_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::JS_ARG), index, {argListOfCircuit}, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewMerge(AddrShift *inList, size_t controlCount)
|
||||
GateRef CircuitBuilder::NewMerge(GateRef *inList, size_t controlCount)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::MERGE), controlCount, controlCount, inList, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewSelectorGate(OpCode opCode, AddrShift control, int valueCounts)
|
||||
GateRef CircuitBuilder::NewSelectorGate(OpCode opCode, GateRef control, int valueCounts, MachineType type)
|
||||
{
|
||||
std::vector<AddrShift> inList;
|
||||
std::vector<GateRef> inList;
|
||||
inList.push_back(control);
|
||||
for (int i = 0; i < valueCounts; i++) {
|
||||
inList.push_back(Circuit::NullGate());
|
||||
}
|
||||
|
||||
return circuit_->NewGate(opCode, valueCounts, inList, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(opCode, valueCounts, inList, MachineType2TypeCode(type));
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewSelectorGate(OpCode opCode, AddrShift control, std::vector<AddrShift> &values,
|
||||
int valueCounts)
|
||||
GateRef CircuitBuilder::NewSelectorGate(OpCode opCode, GateRef control, std::vector<GateRef> &values,
|
||||
int valueCounts, MachineType type)
|
||||
{
|
||||
std::vector<AddrShift> inList;
|
||||
std::vector<GateRef> inList;
|
||||
inList.push_back(control);
|
||||
for (int i = 0; i < valueCounts; i++) {
|
||||
inList.push_back(values[i]);
|
||||
}
|
||||
|
||||
return circuit_->NewGate(opCode, valueCounts, inList, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(opCode, valueCounts, inList, MachineType2TypeCode(type));
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewIntegerConstant(int32_t val)
|
||||
GateRef CircuitBuilder::NewIntegerConstant(int32_t val)
|
||||
{
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::INT32_CONSTANT), val, {constantList}, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewInteger64Constant(int64_t val)
|
||||
GateRef CircuitBuilder::NewInteger64Constant(int64_t val)
|
||||
{
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::INT64_CONSTANT), val, {constantList}, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewBooleanConstant(bool val)
|
||||
GateRef CircuitBuilder::NewBooleanConstant(bool val)
|
||||
{
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::INT32_CONSTANT), val ? 1 : 0, {constantList}, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewDoubleConstant(double val)
|
||||
GateRef CircuitBuilder::NewDoubleConstant(double val)
|
||||
{
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::FLOAT64_CONSTANT), bit_cast<int64_t>(val), {constantList},
|
||||
TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::UndefineConstant()
|
||||
GateRef CircuitBuilder::UndefineConstant(TypeCode type)
|
||||
{
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::INT64_CONSTANT), panda::coretypes::TaggedValue::VALUE_UNDEFINED,
|
||||
{constantList}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::INT64_CONSTANT), TaggedValue::VALUE_UNDEFINED, { constantList }, type);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::HoleConstant()
|
||||
GateRef CircuitBuilder::HoleConstant(TypeCode type)
|
||||
{
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
// NOTE: add bitfield value here
|
||||
return circuit_->NewGate(OpCode(OpCode::JS_CONSTANT), panda::coretypes::TaggedValue::VALUE_HOLE, {constantList},
|
||||
TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::JS_CONSTANT), TaggedValue::VALUE_HOLE, { constantList },
|
||||
type);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::ExceptionConstant()
|
||||
GateRef CircuitBuilder::NullConstant(TypeCode type)
|
||||
{
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
// NOTE: add bitfield value here
|
||||
return circuit_->NewGate(OpCode(OpCode::JS_CONSTANT), panda::coretypes::TaggedValue::VALUE_EXCEPTION,
|
||||
{constantList}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::JS_CONSTANT), TaggedValue::VALUE_NULL, { constantList },
|
||||
type);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::Branch(AddrShift state, AddrShift condition)
|
||||
GateRef CircuitBuilder::ExceptionConstant(TypeCode type)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::IF_BRANCH), 0, {state, condition}, TypeCode::NOTYPE);
|
||||
auto constantList = Circuit::GetCircuitRoot(OpCode(OpCode::CONSTANT_LIST));
|
||||
// NOTE: add bitfield value here
|
||||
return circuit_->NewGate(OpCode(OpCode::JS_CONSTANT), TaggedValue::VALUE_EXCEPTION, { constantList }, type);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::SwitchBranch(AddrShift state, AddrShift index, int caseCounts)
|
||||
GateRef CircuitBuilder::Branch(GateRef state, GateRef condition)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::SWITCH_BRANCH), caseCounts, {state, index}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::IF_BRANCH), 0, { state, condition }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::Return(AddrShift state, AddrShift depend, AddrShift value)
|
||||
GateRef CircuitBuilder::SwitchBranch(GateRef state, GateRef index, int caseCounts)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::SWITCH_BRANCH), caseCounts, { state, index }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::Return(GateRef state, GateRef depend, GateRef value)
|
||||
{
|
||||
auto returnList = Circuit::GetCircuitRoot(OpCode(OpCode::RETURN_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::RETURN), 0, {state, depend, value, returnList}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::RETURN), 0, { state, depend, value, returnList }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::Goto(AddrShift state)
|
||||
GateRef CircuitBuilder::ReturnVoid(GateRef state, GateRef depend)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::ORDINARY_BLOCK), 0, {state}, TypeCode::NOTYPE);
|
||||
auto returnList = Circuit::GetCircuitRoot(OpCode(OpCode::RETURN_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::RETURN_VOID), 0, { state, depend, returnList }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::LoopBegin(AddrShift state)
|
||||
GateRef CircuitBuilder::Goto(GateRef state)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::ORDINARY_BLOCK), 0, { state }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
GateRef CircuitBuilder::LoopBegin(GateRef state)
|
||||
{
|
||||
auto nullGate = Circuit::NullGate();
|
||||
return circuit_->NewGate(OpCode(OpCode::LOOP_BEGIN), 0, {state, nullGate}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::LOOP_BEGIN), 0, { state, nullGate }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::LoopEnd(AddrShift state)
|
||||
GateRef CircuitBuilder::LoopEnd(GateRef state)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::LOOP_BACK), 0, {state}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::LOOP_BACK), 0, { state }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewIfTrue(AddrShift ifBranch)
|
||||
GateRef CircuitBuilder::NewIfTrue(GateRef ifBranch)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::IF_TRUE), 0, {ifBranch}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::IF_TRUE), 0, { ifBranch }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewIfFalse(AddrShift ifBranch)
|
||||
GateRef CircuitBuilder::NewIfFalse(GateRef ifBranch)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::IF_FALSE), 0, {ifBranch}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::IF_FALSE), 0, { ifBranch }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewSwitchCase(AddrShift switchBranch, int32_t value)
|
||||
GateRef CircuitBuilder::NewSwitchCase(GateRef switchBranch, int32_t value)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::SWITCH_CASE), value, {switchBranch}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::SWITCH_CASE), value, { switchBranch }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewDefaultCase(AddrShift switchBranch)
|
||||
GateRef CircuitBuilder::NewDefaultCase(GateRef switchBranch)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::DEFAULT_CASE), 0, {switchBranch}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::DEFAULT_CASE), 0, { switchBranch }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
OpCode CircuitBuilder::GetStoreOpCodeFromMachineType(MachineType type)
|
||||
OpCode CircuitBuilder::GetStoreOpCodeFromMachineType(MachineType type, const char *triple)
|
||||
{
|
||||
switch (type) {
|
||||
case MachineType::INT8_TYPE:
|
||||
case MachineType::INT8:
|
||||
return OpCode(OpCode::INT8_STORE);
|
||||
case MachineType::INT16_TYPE:
|
||||
case MachineType::INT16:
|
||||
return OpCode(OpCode::INT16_STORE);
|
||||
case MachineType::INT32_TYPE:
|
||||
case MachineType::INT32:
|
||||
return OpCode(OpCode::INT32_STORE);
|
||||
case MachineType::INT64_TYPE:
|
||||
case MachineType::INT64:
|
||||
return OpCode(OpCode::INT64_STORE);
|
||||
case MachineType::BOOL_TYPE:
|
||||
case MachineType::BOOL:
|
||||
return OpCode(OpCode::INT32_STORE);
|
||||
case MachineType::UINT8_TYPE:
|
||||
case MachineType::UINT8:
|
||||
return OpCode(OpCode::INT8_STORE);
|
||||
case MachineType::UINT16_TYPE:
|
||||
case MachineType::UINT16:
|
||||
return OpCode(OpCode::INT16_STORE);
|
||||
case MachineType::UINT32_TYPE:
|
||||
case MachineType::UINT32:
|
||||
return OpCode(OpCode::INT32_STORE);
|
||||
case MachineType::UINT64_TYPE:
|
||||
case MachineType::POINTER_TYPE:
|
||||
case MachineType::TAGGED_TYPE:
|
||||
case MachineType::TAGGED_POINTER_TYPE:
|
||||
case MachineType::NATIVE_POINTER:
|
||||
{
|
||||
if (triple == TripleConst::GetLLVMArm32Triple()) {
|
||||
return OpCode(OpCode::INT32_STORE);
|
||||
} else {
|
||||
return OpCode(OpCode::INT64_STORE);
|
||||
}
|
||||
}
|
||||
case MachineType::UINT64:
|
||||
case MachineType::TAGGED:
|
||||
case MachineType::TAGGED_POINTER:
|
||||
return OpCode(OpCode::INT64_STORE);
|
||||
case MachineType::FLOAT32_TYPE:
|
||||
case MachineType::FLOAT32:
|
||||
return OpCode(OpCode::FLOAT32_STORE);
|
||||
case MachineType::FLOAT64_TYPE:
|
||||
case MachineType::FLOAT64:
|
||||
return OpCode(OpCode::FLOAT64_STORE);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
OpCode CircuitBuilder::GetLoadOpCodeFromMachineType(MachineType type)
|
||||
OpCode CircuitBuilder::GetLoadOpCodeFromMachineType(MachineType type, const char *triple)
|
||||
{
|
||||
switch (type) {
|
||||
case MachineType::INT8_TYPE:
|
||||
case MachineType::INT8:
|
||||
return OpCode(OpCode::INT8_LOAD);
|
||||
case MachineType::INT16_TYPE:
|
||||
case MachineType::INT16:
|
||||
return OpCode(OpCode::INT16_LOAD);
|
||||
case MachineType::INT32_TYPE:
|
||||
case MachineType::INT32:
|
||||
return OpCode(OpCode::INT32_LOAD);
|
||||
case MachineType::INT64_TYPE:
|
||||
case MachineType::INT64:
|
||||
return OpCode(OpCode::INT64_LOAD);
|
||||
case MachineType::BOOL_TYPE:
|
||||
case MachineType::BOOL:
|
||||
return OpCode(OpCode::INT32_LOAD);
|
||||
case MachineType::UINT8_TYPE:
|
||||
case MachineType::UINT8:
|
||||
return OpCode(OpCode::INT8_LOAD);
|
||||
case MachineType::UINT16_TYPE:
|
||||
case MachineType::UINT16:
|
||||
return OpCode(OpCode::INT16_LOAD);
|
||||
case MachineType::UINT32_TYPE:
|
||||
case MachineType::UINT32:
|
||||
return OpCode(OpCode::INT32_LOAD);
|
||||
case MachineType::UINT64_TYPE:
|
||||
case MachineType::POINTER_TYPE:
|
||||
case MachineType::TAGGED_TYPE:
|
||||
case MachineType::TAGGED_POINTER_TYPE:
|
||||
case MachineType::NATIVE_POINTER: {
|
||||
if (ArchRelatePtrValueCode(triple) == ValueCode::INT32) {
|
||||
return OpCode(OpCode::INT32_LOAD);
|
||||
} else {
|
||||
return OpCode(OpCode::INT64_LOAD);
|
||||
}
|
||||
}
|
||||
case MachineType::UINT64:
|
||||
case MachineType::TAGGED:
|
||||
case MachineType::TAGGED_POINTER:
|
||||
return OpCode(OpCode::INT64_LOAD);
|
||||
case MachineType::FLOAT32_TYPE:
|
||||
case MachineType::FLOAT32:
|
||||
return OpCode(OpCode::FLOAT32_LOAD);
|
||||
case MachineType::FLOAT64_TYPE:
|
||||
case MachineType::FLOAT64:
|
||||
return OpCode(OpCode::FLOAT64_LOAD);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -221,157 +248,159 @@ OpCode CircuitBuilder::GetLoadOpCodeFromMachineType(MachineType type)
|
||||
OpCode CircuitBuilder::GetSelectOpCodeFromMachineType(MachineType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MachineType::NONE_TYPE:
|
||||
case MachineType::NONE:
|
||||
return OpCode(OpCode::DEPEND_SELECTOR);
|
||||
case MachineType::INT8_TYPE:
|
||||
case MachineType::INT8:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT8);
|
||||
case MachineType::INT16_TYPE:
|
||||
case MachineType::INT16:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT16);
|
||||
case MachineType::INT32_TYPE:
|
||||
case MachineType::INT32:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT32);
|
||||
case MachineType::INT64_TYPE:
|
||||
case MachineType::INT64:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT64);
|
||||
case MachineType::BOOL_TYPE:
|
||||
case MachineType::BOOL:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT1);
|
||||
case MachineType::UINT8_TYPE:
|
||||
case MachineType::UINT8:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT8);
|
||||
case MachineType::UINT16_TYPE:
|
||||
case MachineType::UINT16:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT16);
|
||||
case MachineType::UINT32_TYPE:
|
||||
case MachineType::UINT32:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT32);
|
||||
case MachineType::UINT64_TYPE:
|
||||
case MachineType::POINTER_TYPE:
|
||||
case MachineType::TAGGED_TYPE:
|
||||
case MachineType::TAGGED_POINTER_TYPE:
|
||||
case MachineType::NATIVE_POINTER:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_ANYVALUE);
|
||||
case MachineType::UINT64:
|
||||
case MachineType::TAGGED:
|
||||
case MachineType::TAGGED_POINTER:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_INT64);
|
||||
case MachineType::FLOAT32_TYPE:
|
||||
case MachineType::FLOAT32:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_FLOAT32);
|
||||
case MachineType::FLOAT64_TYPE:
|
||||
case MachineType::FLOAT64:
|
||||
return OpCode(OpCode::VALUE_SELECTOR_FLOAT64);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewDependRelay(AddrShift state, AddrShift depend)
|
||||
GateRef CircuitBuilder::NewDependRelay(GateRef state, GateRef depend)
|
||||
{
|
||||
return circuit_->NewGate(OpCode(OpCode::DEPEND_RELAY), 0, {state, depend}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::DEPEND_RELAY), 0, { state, depend }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewDependAnd(std::initializer_list<AddrShift> args)
|
||||
GateRef CircuitBuilder::NewDependAnd(std::initializer_list<GateRef> args)
|
||||
{
|
||||
std::vector<AddrShift> inputs;
|
||||
std::vector<GateRef> inputs;
|
||||
for (auto arg : args) {
|
||||
inputs.push_back(arg);
|
||||
}
|
||||
return circuit_->NewGate(OpCode(OpCode::DEPEND_AND), args.size(), inputs, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewLoadGate(MachineType type, AddrShift val, AddrShift depend)
|
||||
GateRef CircuitBuilder::NewLoadGate(MachineType type, GateRef val, GateRef depend, const char *triple)
|
||||
{
|
||||
OpCode op = GetLoadOpCodeFromMachineType(type);
|
||||
return circuit_->NewGate(op, static_cast<BitField>(type), {depend, val}, TypeCode::NOTYPE);
|
||||
OpCode op = GetLoadOpCodeFromMachineType(type, triple);
|
||||
return circuit_->NewGate(op, static_cast<BitField>(type), { depend, val }, MachineType2TypeCode(type));
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewStoreGate(MachineType type, AddrShift ptr, AddrShift val, AddrShift depend)
|
||||
GateRef CircuitBuilder::NewStoreGate(MachineType type, GateRef ptr, GateRef val, GateRef depend, const char *triple)
|
||||
{
|
||||
OpCode op = GetStoreOpCodeFromMachineType(type);
|
||||
return circuit_->NewGate(op, static_cast<BitField>(type), {depend, val, ptr}, TypeCode::NOTYPE);
|
||||
OpCode op = GetStoreOpCodeFromMachineType(type, triple);
|
||||
return circuit_->NewGate(op, static_cast<BitField>(type), { depend, val, ptr }, MachineType2TypeCode(type));
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewArithMeticGate(OpCode opcode, AddrShift left, AddrShift right)
|
||||
GateRef CircuitBuilder::NewArithMeticGate(OpCode opcode, GateRef left, GateRef right)
|
||||
{
|
||||
return circuit_->NewGate(opcode, 0, {left, right}, TypeCode::NOTYPE);
|
||||
TypeCode type = circuit_->LoadGatePtr(left)->GetTypeCode();
|
||||
return circuit_->NewGate(opcode, 0, { left, right }, type);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewArithMeticGate(OpCode opcode, AddrShift value)
|
||||
GateRef CircuitBuilder::NewArithMeticGate(OpCode opcode, GateRef value)
|
||||
{
|
||||
return circuit_->NewGate(opcode, 0, {value}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(opcode, 0, { value }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewLogicGate(OpCode opcode, AddrShift left, AddrShift right)
|
||||
GateRef CircuitBuilder::NewLogicGate(OpCode opcode, GateRef left, GateRef right)
|
||||
{
|
||||
return circuit_->NewGate(opcode, static_cast<BitField>(MachineType::BOOL_TYPE), {left, right}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(opcode, static_cast<BitField>(MachineType::BOOL), { left, right }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewLogicGate(OpCode opcode, AddrShift value)
|
||||
GateRef CircuitBuilder::NewLogicGate(OpCode opcode, GateRef value)
|
||||
{
|
||||
return circuit_->NewGate(opcode, static_cast<BitField>(MachineType::BOOL_TYPE), {value}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(opcode, static_cast<BitField>(MachineType::BOOL), { value }, TypeCode::NOTYPE);
|
||||
}
|
||||
|
||||
OpCode CircuitBuilder::GetCallOpCodeFromMachineType(MachineType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MachineType::NONE_TYPE:
|
||||
case MachineType::NONE:
|
||||
return OpCode(OpCode::CALL);
|
||||
case MachineType::INT8_TYPE:
|
||||
case MachineType::INT8:
|
||||
return OpCode(OpCode::INT8_CALL);
|
||||
case MachineType::INT16_TYPE:
|
||||
case MachineType::INT16:
|
||||
return OpCode(OpCode::INT16_CALL);
|
||||
case MachineType::INT32_TYPE:
|
||||
case MachineType::INT32:
|
||||
return OpCode(OpCode::INT32_CALL);
|
||||
case MachineType::INT64_TYPE:
|
||||
case MachineType::INT64:
|
||||
return OpCode(OpCode::INT64_CALL);
|
||||
case MachineType::BOOL_TYPE:
|
||||
case MachineType::BOOL:
|
||||
return OpCode(OpCode::INT1_CALL);
|
||||
case MachineType::UINT8_TYPE:
|
||||
case MachineType::UINT8:
|
||||
return OpCode(OpCode::INT8_CALL);
|
||||
case MachineType::UINT16_TYPE:
|
||||
case MachineType::UINT16:
|
||||
return OpCode(OpCode::INT16_CALL);
|
||||
case MachineType::UINT32_TYPE:
|
||||
case MachineType::UINT32:
|
||||
return OpCode(OpCode::INT32_CALL);
|
||||
case MachineType::UINT64_TYPE:
|
||||
case MachineType::POINTER_TYPE:
|
||||
case MachineType::TAGGED_TYPE:
|
||||
case MachineType::TAGGED_POINTER_TYPE:
|
||||
case MachineType::NATIVE_POINTER:
|
||||
return OpCode(OpCode::ANYVALUE_CALL);
|
||||
case MachineType::UINT64:
|
||||
case MachineType::TAGGED:
|
||||
case MachineType::TAGGED_POINTER:
|
||||
return OpCode(OpCode::INT64_CALL);
|
||||
case MachineType::FLOAT32_TYPE:
|
||||
case MachineType::FLOAT32:
|
||||
return OpCode(OpCode::FLOAT32_CALL);
|
||||
case MachineType::FLOAT64_TYPE:
|
||||
case MachineType::FLOAT64:
|
||||
return OpCode(OpCode::FLOAT64_CALL);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target,
|
||||
std::initializer_list<AddrShift> args)
|
||||
GateRef CircuitBuilder::NewCallGate(StubDescriptor *descriptor, GateRef glue, GateRef target,
|
||||
std::initializer_list<GateRef> args)
|
||||
{
|
||||
std::vector<AddrShift> inputs;
|
||||
// 2 means extra two input gates (target thread)
|
||||
std::vector<GateRef> inputs;
|
||||
// 2 means extra two input gates (target glue)
|
||||
const size_t extraparamCnt = 2;
|
||||
auto dependEntry = Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY));
|
||||
inputs.push_back(dependEntry);
|
||||
inputs.push_back(target);
|
||||
inputs.push_back(thread);
|
||||
inputs.push_back(glue);
|
||||
for (auto arg : args) {
|
||||
inputs.push_back(arg);
|
||||
}
|
||||
OpCode opcode = GetCallOpCodeFromMachineType(descriptor->GetReturnType());
|
||||
if (descriptor->GetReturnType() == MachineType::TAGGED_POINTER_TYPE) {
|
||||
return circuit_->NewGate(opcode, args.size() + extraparamCnt, inputs, TypeCode::TAGGED_POINTER_TYPE);
|
||||
}
|
||||
return circuit_->NewGate(opcode, args.size() + extraparamCnt, inputs, TypeCode::JS_ANY);
|
||||
TypeCode type = MachineType2TypeCode(descriptor->GetReturnType());
|
||||
return circuit_->NewGate(opcode, args.size() + extraparamCnt, inputs, type);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target,
|
||||
AddrShift depend, std::initializer_list<AddrShift> args)
|
||||
GateRef CircuitBuilder::NewCallGate(StubDescriptor *descriptor, GateRef glue, GateRef target,
|
||||
GateRef depend, std::initializer_list<GateRef> args)
|
||||
{
|
||||
std::vector<AddrShift> inputs;
|
||||
std::vector<GateRef> inputs;
|
||||
inputs.push_back(depend);
|
||||
inputs.push_back(target);
|
||||
inputs.push_back(thread);
|
||||
inputs.push_back(glue);
|
||||
for (auto arg : args) {
|
||||
inputs.push_back(arg);
|
||||
}
|
||||
OpCode opcode = GetCallOpCodeFromMachineType(descriptor->GetReturnType());
|
||||
// 2 : 2 means extra two input gates (target thread )
|
||||
return circuit_->NewGate(opcode, args.size() + 2, inputs, TypeCode::JS_ANY);
|
||||
TypeCode type = MachineType2TypeCode(descriptor->GetReturnType());
|
||||
// 2 : 2 means extra two input gates (target glue)
|
||||
return circuit_->NewGate(opcode, args.size() + 2, inputs, type);
|
||||
}
|
||||
|
||||
AddrShift CircuitBuilder::Alloca(int size)
|
||||
GateRef CircuitBuilder::Alloca(int size, TypeCode type)
|
||||
{
|
||||
auto allocaList = Circuit::GetCircuitRoot(OpCode(OpCode::ALLOCA_LIST));
|
||||
return circuit_->NewGate(OpCode(OpCode::ALLOCA), size, {allocaList}, TypeCode::NOTYPE);
|
||||
return circuit_->NewGate(OpCode(OpCode::ALLOCA), size, { allocaList }, type);
|
||||
}
|
||||
} // namespace kungfu
|
||||
|
||||
@@ -28,46 +28,62 @@ public:
|
||||
~CircuitBuilder() = default;
|
||||
NO_MOVE_SEMANTIC(CircuitBuilder);
|
||||
NO_COPY_SEMANTIC(CircuitBuilder);
|
||||
AddrShift NewArguments(size_t index);
|
||||
AddrShift NewMerge(AddrShift *in, size_t controlCount);
|
||||
AddrShift NewSelectorGate(OpCode opcode, AddrShift control, int valueCounts);
|
||||
AddrShift NewSelectorGate(OpCode opcode, AddrShift control, std::vector<AddrShift> &values, int valueCounts);
|
||||
AddrShift NewIntegerConstant(int32_t value);
|
||||
AddrShift NewInteger64Constant(int64_t value);
|
||||
AddrShift NewWord64Constant(uint64_t val);
|
||||
AddrShift NewBooleanConstant(bool value);
|
||||
AddrShift NewDoubleConstant(double value);
|
||||
AddrShift UndefineConstant();
|
||||
AddrShift HoleConstant();
|
||||
AddrShift ExceptionConstant();
|
||||
AddrShift Alloca(int size);
|
||||
AddrShift Branch(AddrShift state, AddrShift condition);
|
||||
AddrShift SwitchBranch(AddrShift state, AddrShift index, int caseCounts);
|
||||
AddrShift Return(AddrShift state, AddrShift depend, AddrShift value);
|
||||
AddrShift Goto(AddrShift state);
|
||||
AddrShift LoopBegin(AddrShift state);
|
||||
AddrShift LoopEnd(AddrShift state);
|
||||
AddrShift NewIfTrue(AddrShift ifBranch);
|
||||
AddrShift NewIfFalse(AddrShift ifBranch);
|
||||
AddrShift NewSwitchCase(AddrShift switchBranch, int32_t value);
|
||||
AddrShift NewDefaultCase(AddrShift switchBranch);
|
||||
AddrShift NewLoadGate(MachineType type, AddrShift val, AddrShift depend);
|
||||
AddrShift NewStoreGate(MachineType type, AddrShift ptr, AddrShift val, AddrShift depend);
|
||||
AddrShift NewDependRelay(AddrShift state, AddrShift depend);
|
||||
AddrShift NewDependAnd(std::initializer_list<AddrShift> args);
|
||||
AddrShift NewArithMeticGate(OpCode opcode, AddrShift left, AddrShift right);
|
||||
AddrShift NewArithMeticGate(OpCode opcode, AddrShift value);
|
||||
AddrShift NewLogicGate(OpCode opcode, AddrShift left, AddrShift right);
|
||||
AddrShift NewLogicGate(OpCode opcode, AddrShift value);
|
||||
AddrShift NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target,
|
||||
std::initializer_list<AddrShift> args);
|
||||
AddrShift NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target,
|
||||
AddrShift depend, std::initializer_list<AddrShift> args);
|
||||
static OpCode GetLoadOpCodeFromMachineType(MachineType type);
|
||||
static OpCode GetStoreOpCodeFromMachineType(MachineType type);
|
||||
GateRef NewArguments(size_t index);
|
||||
GateRef NewMerge(GateRef *in, size_t controlCount);
|
||||
GateRef NewSelectorGate(OpCode opcode, GateRef control, int valueCounts,
|
||||
MachineType type = MachineType::NONE);
|
||||
GateRef NewSelectorGate(OpCode opcode, GateRef control, std::vector<GateRef> &values, int valueCounts,
|
||||
MachineType type = MachineType::NONE);
|
||||
GateRef NewIntegerConstant(int32_t value);
|
||||
GateRef NewInteger64Constant(int64_t value);
|
||||
GateRef NewWord64Constant(uint64_t val);
|
||||
GateRef NewBooleanConstant(bool value);
|
||||
GateRef NewDoubleConstant(double value);
|
||||
GateRef UndefineConstant(TypeCode type);
|
||||
GateRef HoleConstant(TypeCode type);
|
||||
GateRef NullConstant(TypeCode type);
|
||||
GateRef ExceptionConstant(TypeCode type);
|
||||
GateRef Alloca(int size, TypeCode type);
|
||||
GateRef Branch(GateRef state, GateRef condition);
|
||||
GateRef SwitchBranch(GateRef state, GateRef index, int caseCounts);
|
||||
GateRef Return(GateRef state, GateRef depend, GateRef value);
|
||||
GateRef ReturnVoid(GateRef state, GateRef depend);
|
||||
GateRef Goto(GateRef state);
|
||||
GateRef LoopBegin(GateRef state);
|
||||
GateRef LoopEnd(GateRef state);
|
||||
GateRef NewIfTrue(GateRef ifBranch);
|
||||
GateRef NewIfFalse(GateRef ifBranch);
|
||||
GateRef NewSwitchCase(GateRef switchBranch, int32_t value);
|
||||
GateRef NewDefaultCase(GateRef switchBranch);
|
||||
GateRef NewLoadGate(MachineType type, GateRef val, GateRef depend, const char *triple);
|
||||
GateRef NewStoreGate(MachineType type, GateRef ptr, GateRef val, GateRef depend, const char *triple);
|
||||
GateRef NewDependRelay(GateRef state, GateRef depend);
|
||||
GateRef NewDependAnd(std::initializer_list<GateRef> args);
|
||||
GateRef NewArithMeticGate(OpCode opcode, GateRef left, GateRef right);
|
||||
GateRef NewArithMeticGate(OpCode opcode, GateRef value);
|
||||
GateRef NewLogicGate(OpCode opcode, GateRef left, GateRef right);
|
||||
GateRef NewLogicGate(OpCode opcode, GateRef value);
|
||||
GateRef NewCallGate(StubDescriptor *descriptor, GateRef glue, GateRef target,
|
||||
std::initializer_list<GateRef> args);
|
||||
GateRef NewCallGate(StubDescriptor *descriptor, GateRef glue, GateRef target,
|
||||
GateRef depend, std::initializer_list<GateRef> args);
|
||||
static OpCode GetLoadOpCodeFromMachineType(MachineType type, const char *triple);
|
||||
static OpCode GetStoreOpCodeFromMachineType(MachineType type, const char *triple);
|
||||
static OpCode GetSelectOpCodeFromMachineType(MachineType type);
|
||||
static OpCode GetCallOpCodeFromMachineType(MachineType type);
|
||||
|
||||
static TypeCode MachineType2TypeCode(MachineType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MachineType::TAGGED_POINTER:
|
||||
return TypeCode::TAGGED_POINTER;
|
||||
case MachineType::TAGGED:
|
||||
return TypeCode::JS_ANY;
|
||||
default:
|
||||
return TypeCode::NOTYPE;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Circuit *circuit_;
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "circuit.h"
|
||||
|
||||
namespace kungfu {
|
||||
using ControlFlowGraph = std::vector<std::vector<AddrShift>>;
|
||||
using ControlFlowGraph = std::vector<std::vector<GateRef>>;
|
||||
class CodeGeneratorImpl {
|
||||
public:
|
||||
CodeGeneratorImpl() = default;
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
|
||||
class CodeGenerator {
|
||||
public:
|
||||
explicit CodeGenerator(CodeGeneratorImpl *impl) : impl_(impl) {}
|
||||
explicit CodeGenerator(std::unique_ptr<CodeGeneratorImpl> &impl, const char* triple) : impl_(std::move(impl)) {}
|
||||
~CodeGenerator() = default;
|
||||
void Run(Circuit *circuit, const ControlFlowGraph &graph, int index)
|
||||
{
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
CodeGeneratorImpl *impl_;
|
||||
std::unique_ptr<CodeGeneratorImpl> impl_{nullptr};
|
||||
};
|
||||
} // namespace kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_CODE_GENERATOR_H
|
||||
@@ -33,8 +33,8 @@ fi
|
||||
cd ${BASE_HOME}/third_party/llvm-project
|
||||
if [ ! -d "build" ];then
|
||||
git checkout -b local llvmorg-10.0.1
|
||||
cp ../../ark/js_runtime/ecmascript/compiler/llvm/llvm.patch .
|
||||
git apply --reject llvm.patch
|
||||
cp ../../ark/js_runtime/ecmascript/compiler/llvm/llvm_new.patch .
|
||||
git apply --reject llvm_new.patch
|
||||
mkdir build && cd build
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DBUILD_ARK_GC_SUPPORT=ON -DLLVM_ENABLE_TERMINFO=OFF DLLVM_STATIC_LINK_CXX_STDLIB=OFF -DLLVM_ENABLE_ZLIB=OFF ../llvm
|
||||
ninja
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecmascript/mem/tagged_object.h"
|
||||
#ifndef ECMASCRIPT_COMPILER_MACROS_H
|
||||
#define ECMASCRIPT_COMPILER_MACROS_H
|
||||
|
||||
#include "ecmascript/js_hclass-inl.h"
|
||||
#include "ecmascript/base/config.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
size_t TaggedObject::GetObjectSize()
|
||||
{
|
||||
JSHClass *cls = GetClass();
|
||||
return cls->SizeFromJSHClass(cls->GetObjectType(), this);
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
#define ECMASCRIPT_ENABLE_COMPILER_LOG 0
|
||||
|
||||
#define COMPILER_LOG(level) ECMASCRIPT_ENABLE_COMPILER_LOG &&LOG_ECMA(level)
|
||||
|
||||
#endif // ECMASCRIPT_COMPILER_MACROS_H
|
||||
+1256
-1020
File diff suppressed because it is too large
Load Diff
+284
-113
@@ -17,33 +17,36 @@
|
||||
#define ECMASCRIPT_COMPILER_FASTPATH_STUB_H
|
||||
|
||||
#include "ecmascript/compiler/fast_stub_define.h"
|
||||
#include "ecmascript/compiler/stub.h"
|
||||
#include "ecmascript/compiler/stub-inl.h"
|
||||
|
||||
namespace kungfu {
|
||||
class FastArrayLoadElementStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastArrayLoadElementStub(Circuit *circuit) : Stub("FastArrayLoadElement", 2, circuit) {}
|
||||
~FastArrayLoadElementStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastArrayLoadElementStub);
|
||||
NO_COPY_SEMANTIC(FastArrayLoadElementStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
#ifdef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
class FastAddStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastAddStub(Circuit *circuit) : Stub("FastAdd", 2, circuit) {}
|
||||
explicit FastAddStub(Circuit *circuit, const char* triple) : Stub("FastAdd", 2, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_FRAME);
|
||||
}
|
||||
~FastAddStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastAddStub);
|
||||
NO_COPY_SEMANTIC(FastAddStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastMulGCTestStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit FastMulGCTestStub(Circuit *circuit, const char* triple) : Stub("FastMulGCTest", 3, circuit, triple) {}
|
||||
~FastMulGCTestStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastMulGCTestStub);
|
||||
NO_COPY_SEMANTIC(FastMulGCTestStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
class FastSubStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastSubStub(Circuit *circuit) : Stub("FastSub", 2, circuit) {}
|
||||
explicit FastSubStub(Circuit *circuit, const char* triple) : Stub("FastSub", 2, circuit, triple) {}
|
||||
~FastSubStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastSubStub);
|
||||
NO_COPY_SEMANTIC(FastSubStub);
|
||||
@@ -53,119 +56,27 @@ public:
|
||||
class FastMulStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastMulStub(Circuit *circuit) : Stub("FastMul", 2, circuit) {}
|
||||
explicit FastMulStub(Circuit *circuit, const char* triple) : Stub("FastMul", 2, circuit, triple) {}
|
||||
~FastMulStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastMulStub);
|
||||
NO_COPY_SEMANTIC(FastMulStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastMulGCTestStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit FastMulGCTestStub(Circuit *circuit) : Stub("FastMulGCTest", 3, circuit) {}
|
||||
~FastMulGCTestStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastMulGCTestStub);
|
||||
NO_COPY_SEMANTIC(FastMulGCTestStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastDivStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastDivStub(Circuit *circuit) : Stub("FastDiv", 2, circuit) {}
|
||||
explicit FastDivStub(Circuit *circuit, const char* triple) : Stub("FastDiv", 2, circuit, triple) {}
|
||||
~FastDivStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastDivStub);
|
||||
NO_COPY_SEMANTIC(FastDivStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FindOwnElementStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit FindOwnElementStub(Circuit *circuit) : Stub("FindOwnElement", 3, circuit) {}
|
||||
~FindOwnElementStub() = default;
|
||||
NO_MOVE_SEMANTIC(FindOwnElementStub);
|
||||
NO_COPY_SEMANTIC(FindOwnElementStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class GetElementStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetElementStub(Circuit *circuit) : Stub("GetElement", 3, circuit)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~GetElementStub() = default;
|
||||
NO_MOVE_SEMANTIC(GetElementStub);
|
||||
NO_COPY_SEMANTIC(GetElementStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FindOwnElement2Stub : public Stub {
|
||||
public:
|
||||
// 6 : 6 means argument counts
|
||||
explicit FindOwnElement2Stub(Circuit *circuit) : Stub("FindOwnElement2", 6, circuit) {}
|
||||
~FindOwnElement2Stub() = default;
|
||||
NO_MOVE_SEMANTIC(FindOwnElement2Stub);
|
||||
NO_COPY_SEMANTIC(FindOwnElement2Stub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class SetElementStub : public Stub {
|
||||
public:
|
||||
// 5 : 5 means argument counts
|
||||
explicit SetElementStub(Circuit *circuit) : Stub("SetElement", 5, circuit) {}
|
||||
~SetElementStub() = default;
|
||||
NO_MOVE_SEMANTIC(SetElementStub);
|
||||
NO_COPY_SEMANTIC(SetElementStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class GetPropertyByIndexStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetPropertyByIndexStub(Circuit *circuit) : Stub("GetPropertyByIndex", 3, circuit)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~GetPropertyByIndexStub() = default;
|
||||
NO_MOVE_SEMANTIC(GetPropertyByIndexStub);
|
||||
NO_COPY_SEMANTIC(GetPropertyByIndexStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class SetPropertyByIndexStub : public Stub {
|
||||
public:
|
||||
// 4 : 4 means argument counts
|
||||
explicit SetPropertyByIndexStub(Circuit *circuit) : Stub("SetPropertyByIndex", 4, circuit)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~SetPropertyByIndexStub() = default;
|
||||
NO_MOVE_SEMANTIC(SetPropertyByIndexStub);
|
||||
NO_COPY_SEMANTIC(SetPropertyByIndexStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class GetPropertyByNameStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetPropertyByNameStub(Circuit *circuit) : Stub("GetPropertyByName", 3, circuit)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~GetPropertyByNameStub() = default;
|
||||
NO_MOVE_SEMANTIC(GetPropertyByNameStub);
|
||||
NO_COPY_SEMANTIC(GetPropertyByNameStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastModStub : public Stub {
|
||||
public:
|
||||
// 3 means argument counts
|
||||
explicit FastModStub(Circuit *circuit) : Stub("FastMod", 3, circuit)
|
||||
explicit FastModStub(Circuit *circuit, const char* triple) : Stub("FastMod", 3, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
@@ -178,7 +89,215 @@ public:
|
||||
class FastTypeOfStub : public Stub {
|
||||
public:
|
||||
// 2 means argument counts
|
||||
explicit FastTypeOfStub(Circuit *circuit) : Stub("FastTypeOf", 2, circuit) {}
|
||||
explicit FastTypeOfStub(Circuit *circuit, const char* triple) : Stub("FastTypeOf", 2, circuit, triple) {}
|
||||
~FastTypeOfStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastTypeOfStub);
|
||||
NO_COPY_SEMANTIC(FastTypeOfStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastEqualStub : public Stub {
|
||||
public:
|
||||
// 2 means argument counts
|
||||
explicit FastEqualStub(Circuit *circuit, const char* triple) : Stub("FastEqual", 2, circuit, triple) {}
|
||||
~FastEqualStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastEqualStub);
|
||||
NO_COPY_SEMANTIC(FastEqualStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class GetPropertyByIndexStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetPropertyByIndexStub(Circuit *circuit, const char* triple)
|
||||
: Stub("GetPropertyByIndex", 3, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~GetPropertyByIndexStub() = default;
|
||||
NO_MOVE_SEMANTIC(GetPropertyByIndexStub);
|
||||
NO_COPY_SEMANTIC(GetPropertyByIndexStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class SetPropertyByIndexStub : public Stub {
|
||||
public:
|
||||
// 4 : 4 means argument counts
|
||||
explicit SetPropertyByIndexStub(Circuit *circuit, const char* triple)
|
||||
: Stub("SetPropertyByIndex", 4, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~SetPropertyByIndexStub() = default;
|
||||
NO_MOVE_SEMANTIC(SetPropertyByIndexStub);
|
||||
NO_COPY_SEMANTIC(SetPropertyByIndexStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class GetPropertyByNameStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetPropertyByNameStub(Circuit *circuit, const char* triple)
|
||||
: Stub("GetPropertyByName", 3, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~GetPropertyByNameStub() = default;
|
||||
NO_MOVE_SEMANTIC(GetPropertyByNameStub);
|
||||
NO_COPY_SEMANTIC(GetPropertyByNameStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
#else
|
||||
class FastAddStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastAddStub(Circuit *circuit, const char* triple) : Stub("FastAdd", 2, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_FRAME);
|
||||
}
|
||||
~FastAddStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastAddStub);
|
||||
NO_COPY_SEMANTIC(FastAddStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastSubStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastSubStub(Circuit *circuit, const char* triple) : Stub("FastSub", 2, circuit, triple) {}
|
||||
~FastSubStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastSubStub);
|
||||
NO_COPY_SEMANTIC(FastSubStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastMulStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastMulStub(Circuit *circuit, const char* triple) : Stub("FastMul", 2, circuit, triple) {}
|
||||
~FastMulStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastMulStub);
|
||||
NO_COPY_SEMANTIC(FastMulStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastMulGCTestStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit FastMulGCTestStub(Circuit *circuit, const char* triple) : Stub("FastMulGCTest", 3, circuit, triple) {}
|
||||
~FastMulGCTestStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastMulGCTestStub);
|
||||
NO_COPY_SEMANTIC(FastMulGCTestStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastDivStub : public Stub {
|
||||
public:
|
||||
// 2 : 2 means argument counts
|
||||
explicit FastDivStub(Circuit *circuit, const char* triple) : Stub("FastDiv", 2, circuit, triple) {}
|
||||
~FastDivStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastDivStub);
|
||||
NO_COPY_SEMANTIC(FastDivStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FindOwnElement2Stub : public Stub {
|
||||
public:
|
||||
// 6 : 6 means argument counts
|
||||
explicit FindOwnElement2Stub(Circuit *circuit, const char* triple) : Stub("FindOwnElement2", 6, circuit, triple) {}
|
||||
~FindOwnElement2Stub() = default;
|
||||
NO_MOVE_SEMANTIC(FindOwnElement2Stub);
|
||||
NO_COPY_SEMANTIC(FindOwnElement2Stub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class GetPropertyByIndexStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetPropertyByIndexStub(Circuit *circuit, const char* triple)
|
||||
: Stub("GetPropertyByIndex", 3, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~GetPropertyByIndexStub() = default;
|
||||
NO_MOVE_SEMANTIC(GetPropertyByIndexStub);
|
||||
NO_COPY_SEMANTIC(GetPropertyByIndexStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class SetPropertyByIndexStub : public Stub {
|
||||
public:
|
||||
// 4 : 4 means argument counts
|
||||
explicit SetPropertyByIndexStub(Circuit *circuit, const char* triple)
|
||||
: Stub("SetPropertyByIndex", 4, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~SetPropertyByIndexStub() = default;
|
||||
NO_MOVE_SEMANTIC(SetPropertyByIndexStub);
|
||||
NO_COPY_SEMANTIC(SetPropertyByIndexStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class GetPropertyByNameStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetPropertyByNameStub(Circuit *circuit, const char* triple)
|
||||
: Stub("GetPropertyByName", 3, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~GetPropertyByNameStub() = default;
|
||||
NO_MOVE_SEMANTIC(GetPropertyByNameStub);
|
||||
NO_COPY_SEMANTIC(GetPropertyByNameStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class SetPropertyByNameStub : public Stub {
|
||||
public:
|
||||
// 4 : 4 means argument counts
|
||||
explicit SetPropertyByNameStub(Circuit *circuit, const char* triple)
|
||||
: Stub("SetPropertyByName", 4, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~SetPropertyByNameStub() = default;
|
||||
NO_MOVE_SEMANTIC(SetPropertyByNameStub);
|
||||
NO_COPY_SEMANTIC(SetPropertyByNameStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class SetPropertyByNameWithOwnStub : public Stub {
|
||||
public:
|
||||
// 4 : 4 means argument counts
|
||||
explicit SetPropertyByNameWithOwnStub(Circuit *circuit, const char* triple)
|
||||
: Stub("SetPropertyByNameWithOwn", 4, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~SetPropertyByNameWithOwnStub() = default;
|
||||
NO_MOVE_SEMANTIC(SetPropertyByNameWithOwnStub);
|
||||
NO_COPY_SEMANTIC(SetPropertyByNameWithOwnStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastModStub : public Stub {
|
||||
public:
|
||||
// 3 means argument counts
|
||||
explicit FastModStub(Circuit *circuit, const char* triple) : Stub("FastMod", 3, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~FastModStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastModStub);
|
||||
NO_COPY_SEMANTIC(FastModStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class FastTypeOfStub : public Stub {
|
||||
public:
|
||||
// 2 means argument counts
|
||||
explicit FastTypeOfStub(Circuit *circuit, const char* triple) : Stub("FastTypeOf", 2, circuit, triple) {}
|
||||
~FastTypeOfStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastTypeOfStub);
|
||||
NO_COPY_SEMANTIC(FastTypeOfStub);
|
||||
@@ -188,7 +307,8 @@ public:
|
||||
class FunctionCallInternalStub : public Stub {
|
||||
public:
|
||||
// 5 : 5 means argument counts
|
||||
explicit FunctionCallInternalStub(Circuit *circuit) : Stub("FunctionCallInternal", 5, circuit) {}
|
||||
explicit FunctionCallInternalStub(Circuit *circuit, const char* triple)
|
||||
: Stub("FunctionCallInternal", 5, circuit, triple) {}
|
||||
~FunctionCallInternalStub() = default;
|
||||
NO_MOVE_SEMANTIC(FunctionCallInternalStub);
|
||||
NO_COPY_SEMANTIC(FunctionCallInternalStub);
|
||||
@@ -198,7 +318,8 @@ public:
|
||||
class GetPropertyByValueStub : public Stub {
|
||||
public:
|
||||
// 3 : 3 means argument counts
|
||||
explicit GetPropertyByValueStub(Circuit *circuit) : Stub("FastGetPropertyByValue", 3, circuit)
|
||||
explicit GetPropertyByValueStub(Circuit *circuit, const char* triple)
|
||||
: Stub("FastGetPropertyByValue", 3, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
@@ -211,7 +332,8 @@ public:
|
||||
class SetPropertyByValueStub : public Stub {
|
||||
public:
|
||||
// 4 : 4 means argument counts
|
||||
explicit SetPropertyByValueStub(Circuit *circuit) : Stub("FastSetPropertyByValue", 4, circuit)
|
||||
explicit SetPropertyByValueStub(Circuit *circuit, const char* triple)
|
||||
: Stub("FastSetPropertyByValue", 4, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
@@ -224,12 +346,61 @@ public:
|
||||
class FastEqualStub : public Stub {
|
||||
public:
|
||||
// 2 means argument counts
|
||||
explicit FastEqualStub(Circuit *circuit) : Stub("FastEqual", 2, circuit) {}
|
||||
explicit FastEqualStub(Circuit *circuit, const char* triple) : Stub("FastEqual", 2, circuit, triple) {}
|
||||
~FastEqualStub() = default;
|
||||
NO_MOVE_SEMANTIC(FastEqualStub);
|
||||
NO_COPY_SEMANTIC(FastEqualStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class TryLoadICByNameStub : public Stub {
|
||||
public:
|
||||
// 4 : 4 means argument counts
|
||||
explicit TryLoadICByNameStub(Circuit *circuit, const char* triple) : Stub("TryLoadICByName", 4, circuit, triple) {}
|
||||
~TryLoadICByNameStub() = default;
|
||||
NO_MOVE_SEMANTIC(TryLoadICByNameStub);
|
||||
NO_COPY_SEMANTIC(TryLoadICByNameStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class TryLoadICByValueStub : public Stub {
|
||||
public:
|
||||
// 5 : 5 means argument counts
|
||||
explicit TryLoadICByValueStub(Circuit *circuit, const char* triple)
|
||||
: Stub("TryLoadICByValue", 5, circuit, triple) {}
|
||||
~TryLoadICByValueStub() = default;
|
||||
NO_MOVE_SEMANTIC(TryLoadICByValueStub);
|
||||
NO_COPY_SEMANTIC(TryLoadICByValueStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class TryStoreICByNameStub : public Stub {
|
||||
public:
|
||||
// 5 : 5 means argument counts
|
||||
explicit TryStoreICByNameStub(Circuit *circuit, const char* triple) : Stub("TryStoreICByName", 5, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~TryStoreICByNameStub() = default;
|
||||
NO_MOVE_SEMANTIC(TryStoreICByNameStub);
|
||||
NO_COPY_SEMANTIC(TryStoreICByNameStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
|
||||
class TryStoreICByValueStub : public Stub {
|
||||
public:
|
||||
// 6 : 6 means argument counts
|
||||
explicit TryStoreICByValueStub(Circuit *circuit, const char* triple)
|
||||
: Stub("TryStoreICByValue", 6, circuit, triple)
|
||||
{
|
||||
circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
}
|
||||
~TryStoreICByValueStub() = default;
|
||||
NO_MOVE_SEMANTIC(TryStoreICByValueStub);
|
||||
NO_COPY_SEMANTIC(TryStoreICByValueStub);
|
||||
void GenerateCircuit() override;
|
||||
};
|
||||
#endif
|
||||
} // namespace kungfu
|
||||
|
||||
#endif // ECMASCRIPT_COMPILER_FASTPATH_STUB_H
|
||||
|
||||
@@ -18,23 +18,35 @@
|
||||
|
||||
namespace kungfu {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define EXTERNAL_RUNTIMESTUB_LIST(V) \
|
||||
V(AddElementInternal, 5) \
|
||||
V(CallSetter, 4) \
|
||||
V(CallGetter, 4) \
|
||||
V(AccessorGetter, 4) \
|
||||
V(ThrowTypeError, 2) \
|
||||
V(JSProxySetProperty, 6) \
|
||||
V(GetHash32, 2) \
|
||||
V(FindElementWithCache, 4) \
|
||||
V(Execute, 5) \
|
||||
V(StringGetHashCode, 1) \
|
||||
V(FloatMod, 2) \
|
||||
V(SetValueWithBarrier, 4) \
|
||||
V(GetTaggedArrayPtrTest, 1) \
|
||||
V(NewInternalString, 2)
|
||||
#define EXTERNAL_RUNTIMESTUB_LIST(V) \
|
||||
V(AddElementInternal, 5) \
|
||||
V(CallSetter, 5) \
|
||||
V(CallSetter2, 4) \
|
||||
V(CallGetter, 3) \
|
||||
V(CallGetter2, 4) \
|
||||
V(CallInternalGetter, 3) \
|
||||
V(ThrowTypeError, 2) \
|
||||
V(JSProxySetProperty, 6) \
|
||||
V(GetHash32, 2) \
|
||||
V(FindElementWithCache, 4) \
|
||||
V(Execute, 5) \
|
||||
V(StringGetHashCode, 1) \
|
||||
V(FloatMod, 2) \
|
||||
V(GetTaggedArrayPtrTest, 1) \
|
||||
V(NewInternalString, 2) \
|
||||
V(NewTaggedArray, 2) \
|
||||
V(CopyArray, 3) \
|
||||
V(NameDictPutIfAbsent, 7) \
|
||||
V(SetValueWithBarrier, 4) \
|
||||
V(PropertiesSetValue, 6) \
|
||||
V(TaggedArraySetValue, 6) \
|
||||
V(NewEcmaDynClass, 3) \
|
||||
V(UpdateLayOutAndAddTransition, 5) \
|
||||
V(NoticeThroughChainAndRefreshUser, 3) \
|
||||
V(DebugPrint, 1)
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#ifdef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
#define FAST_RUNTIME_STUB_LIST(V) \
|
||||
V(FastAdd, 2) \
|
||||
V(FastSub, 2) \
|
||||
@@ -47,9 +59,8 @@ namespace kungfu {
|
||||
V(IsSpecialIndexedObjForSet, 1) \
|
||||
V(IsSpecialIndexedObjForGet, 1) \
|
||||
V(GetPropertyByName, 3) \
|
||||
V(GetElement, 2) \
|
||||
V(SetPropertyByName, 5) \
|
||||
V(SetElement, 5) \
|
||||
V(SetPropertyByName, 4) \
|
||||
V(SetPropertyByNameWithOwn, 4) \
|
||||
V(SetGlobalOwnProperty, 5) \
|
||||
V(GetGlobalOwnProperty, 3) \
|
||||
V(SetOwnPropertyByName, 4) \
|
||||
@@ -57,23 +68,39 @@ namespace kungfu {
|
||||
V(FastSetProperty, 5) \
|
||||
V(FastGetProperty, 3) \
|
||||
V(FindOwnProperty, 6) \
|
||||
V(FindOwnElement, 2) \
|
||||
V(NewLexicalEnvDyn, 4) \
|
||||
V(FindOwnProperty2, 6) \
|
||||
V(FindOwnElement2, 6) \
|
||||
V(GetPropertyByIndex, 3) \
|
||||
V(FunctionCallInternal, 5) \
|
||||
V(SetPropertyByIndex, 4) \
|
||||
V(GetPropertyByValue, 3) \
|
||||
V(SetPropertyByValue, 4) \
|
||||
V(FastMulGCTest, 3) \
|
||||
V(TryLoadICByName, 4) \
|
||||
V(TryLoadICByValue, 5) \
|
||||
V(TryStoreICByName, 5) \
|
||||
V(TryStoreICByValue, 6)
|
||||
#else
|
||||
#define FAST_RUNTIME_STUB_LIST(V) \
|
||||
V(FastAdd, 2) \
|
||||
V(FastSub, 2) \
|
||||
V(FastMul, 2) \
|
||||
V(FastDiv, 2) \
|
||||
V(FastMod, 3) \
|
||||
V(FastEqual, 2) \
|
||||
V(FastTypeOf, 2) \
|
||||
V(FastMulGCTest, 3)
|
||||
#endif
|
||||
|
||||
#ifndef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define TEST_FUNC_LIST(V) \
|
||||
V(FastLoadElement, 2) \
|
||||
V(PhiGateTest, 1) \
|
||||
V(LoopTest, 1) \
|
||||
V(LoopTest1, 1)
|
||||
#else
|
||||
#define TEST_FUNC_LIST(V)
|
||||
#endif
|
||||
|
||||
#define CALL_STUB_LIST(V) \
|
||||
FAST_RUNTIME_STUB_LIST(V) \
|
||||
|
||||
+209
-181
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/compiler/gate.h"
|
||||
#include "triple.h"
|
||||
|
||||
namespace kungfu {
|
||||
constexpr size_t ONE_DEPEND = 1;
|
||||
@@ -41,7 +42,7 @@ Properties OpCode::GetProperties() const
|
||||
#define NO_ROOT (std::nullopt)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define GENERAL_STATE (NOP)
|
||||
switch (this->op) {
|
||||
switch (op_) {
|
||||
// SHARED
|
||||
case NOP:
|
||||
case CIRCUIT_ROOT:
|
||||
@@ -57,6 +58,8 @@ Properties OpCode::GetProperties() const
|
||||
return {NOVALUE, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CIRCUIT_ROOT)};
|
||||
case RETURN:
|
||||
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(ANYVALUE), OpCode(RETURN_LIST)};
|
||||
case RETURN_VOID:
|
||||
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, NO_VALUE, OpCode(RETURN_LIST)};
|
||||
case THROW:
|
||||
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), ONE_DEPEND, VALUE(JSValueCode()), OpCode(THROW_LIST)};
|
||||
case ORDINARY_BLOCK:
|
||||
@@ -93,6 +96,8 @@ Properties OpCode::GetProperties() const
|
||||
return {FLOAT32, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, MANY_VALUE(FLOAT32), NO_ROOT};
|
||||
case VALUE_SELECTOR_FLOAT64:
|
||||
return {FLOAT64, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, MANY_VALUE(FLOAT64), NO_ROOT};
|
||||
case VALUE_SELECTOR_ANYVALUE:
|
||||
return {ANYVALUE, STATE(OpCode(GENERAL_STATE)), NO_DEPEND, MANY_VALUE(ANYVALUE), NO_ROOT};
|
||||
case DEPEND_SELECTOR:
|
||||
return {NOVALUE, STATE(OpCode(GENERAL_STATE)), MANY_DEPEND, NO_VALUE, NO_ROOT};
|
||||
case DEPEND_RELAY:
|
||||
@@ -133,23 +138,25 @@ Properties OpCode::GetProperties() const
|
||||
return {JSValueCode(), NO_STATE, NO_DEPEND, VALUE(JSValueCode()), NO_ROOT};
|
||||
// Middle Level IR
|
||||
case CALL:
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case INT1_CALL:
|
||||
return {INT1, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {INT1, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case INT8_CALL:
|
||||
return {INT8, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {INT8, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case INT16_CALL:
|
||||
return {INT16, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {INT16, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case INT32_CALL:
|
||||
return {INT32, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {INT32, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case INT64_CALL:
|
||||
return {INT64, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {INT64, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case FLOAT32_CALL:
|
||||
return {FLOAT32, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {FLOAT32, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case FLOAT64_CALL:
|
||||
return {FLOAT64, NO_STATE, ONE_DEPEND, MANY_VALUE(PtrValueCode(), ANYVALUE), NO_ROOT};
|
||||
return {FLOAT64, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case ANYVALUE_CALL:
|
||||
return {ANYVALUE, NO_STATE, ONE_DEPEND, MANY_VALUE(ANYVALUE, ANYVALUE), NO_ROOT};
|
||||
case ALLOCA:
|
||||
return {PtrValueCode(), NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ALLOCA_LIST)};
|
||||
return {ANYVALUE, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ALLOCA_LIST)};
|
||||
case INT1_ARG:
|
||||
return {INT1, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ARG_LIST)};
|
||||
case INT8_ARG:
|
||||
@@ -166,7 +173,7 @@ Properties OpCode::GetProperties() const
|
||||
return {FLOAT64, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(ARG_LIST)};
|
||||
case MUTABLE_DATA:
|
||||
case CONST_DATA:
|
||||
return {PtrValueCode(), NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
|
||||
return {ANYVALUE, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
|
||||
case INT1_CONSTANT:
|
||||
return {INT1, NO_STATE, NO_DEPEND, NO_VALUE, OpCode(CONSTANT_LIST)};
|
||||
case INT8_CONSTANT:
|
||||
@@ -273,39 +280,41 @@ Properties OpCode::GetProperties() const
|
||||
case FLOAT64_EQ:
|
||||
return {INT1, NO_STATE, NO_DEPEND, VALUE(FLOAT64, FLOAT64), NO_ROOT};
|
||||
case INT8_LOAD:
|
||||
return {INT8, NO_STATE, ONE_DEPEND, VALUE(PtrValueCode()), NO_ROOT};
|
||||
return {INT8, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
|
||||
case INT16_LOAD:
|
||||
return {INT16, NO_STATE, ONE_DEPEND, VALUE(PtrValueCode()), NO_ROOT};
|
||||
return {INT16, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
|
||||
case INT32_LOAD:
|
||||
return {INT32, NO_STATE, ONE_DEPEND, VALUE(PtrValueCode()), NO_ROOT};
|
||||
return {INT32, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
|
||||
case INT64_LOAD:
|
||||
return {INT64, NO_STATE, ONE_DEPEND, VALUE(PtrValueCode()), NO_ROOT};
|
||||
return {INT64, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
|
||||
case FLOAT32_LOAD:
|
||||
return {FLOAT32, NO_STATE, ONE_DEPEND, VALUE(PtrValueCode()), NO_ROOT};
|
||||
return {FLOAT32, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
|
||||
case FLOAT64_LOAD:
|
||||
return {FLOAT64, NO_STATE, ONE_DEPEND, VALUE(PtrValueCode()), NO_ROOT};
|
||||
return {FLOAT64, NO_STATE, ONE_DEPEND, VALUE(ANYVALUE), NO_ROOT};
|
||||
case INT8_STORE:
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT8, PtrValueCode()), NO_ROOT};
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT8, ANYVALUE), NO_ROOT};
|
||||
case INT16_STORE:
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT16, PtrValueCode()), NO_ROOT};
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT16, ANYVALUE), NO_ROOT};
|
||||
case INT32_STORE:
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT32, PtrValueCode()), NO_ROOT};
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT32, ANYVALUE), NO_ROOT};
|
||||
case INT64_STORE:
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT64, PtrValueCode()), NO_ROOT};
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(INT64, ANYVALUE), NO_ROOT};
|
||||
case FLOAT32_STORE:
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(FLOAT32, PtrValueCode()), NO_ROOT};
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(FLOAT32, ANYVALUE), NO_ROOT};
|
||||
case FLOAT64_STORE:
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(FLOAT64, PtrValueCode()), NO_ROOT};
|
||||
return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(FLOAT64, ANYVALUE), NO_ROOT};
|
||||
case INT32_TO_FLOAT64:
|
||||
return {FLOAT64, NO_STATE, NO_DEPEND, VALUE(INT32), NO_ROOT};
|
||||
case FLOAT64_TO_INT32:
|
||||
return {INT32, NO_STATE, NO_DEPEND, VALUE(FLOAT64), NO_ROOT};
|
||||
case TAGGED_POINTER_TO_INT64:
|
||||
return {INT64, NO_STATE, NO_DEPEND, VALUE(ANYVALUE), NO_ROOT};
|
||||
case BITCAST_INT64_TO_FLOAT64:
|
||||
return {FLOAT64, NO_STATE, NO_DEPEND, VALUE(INT64), NO_ROOT};
|
||||
case BITCAST_FLOAT64_TO_INT64:
|
||||
return {INT64, NO_STATE, NO_DEPEND, VALUE(FLOAT64), NO_ROOT};
|
||||
default:
|
||||
std::cerr << "Please complete OpCode properties (OpCode=" << this->op << ")" << std::endl;
|
||||
std::cerr << "Please complete OpCode properties (OpCode=" << op_ << ")" << std::endl;
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef STATE
|
||||
@@ -333,6 +342,7 @@ std::string OpCode::Str() const
|
||||
{ALLOCA_LIST, "ALLOCA_LIST"},
|
||||
{ARG_LIST, "ARG_LIST"},
|
||||
{RETURN, "RETURN"},
|
||||
{RETURN_VOID, "RETURN_VOID"},
|
||||
{THROW, "THROW"},
|
||||
{ORDINARY_BLOCK, "ORDINARY_BLOCK"},
|
||||
{IF_BRANCH, "IF_BRANCH"},
|
||||
@@ -391,6 +401,7 @@ std::string OpCode::Str() const
|
||||
{INT64_CALL, "INT64_CALL"},
|
||||
{FLOAT32_CALL, "FLOAT32_CALL"},
|
||||
{FLOAT64_CALL, "FLOAT64_CALL"},
|
||||
{ANYVALUE_CALL, "ANYVALUE_CALL"},
|
||||
{TAGGED_POINTER_CALL, "TAGGED_POINTER_CALL"},
|
||||
{ALLOCA, "ALLOCA"},
|
||||
{INT1_ARG, "INT1_ARG"},
|
||||
@@ -492,19 +503,21 @@ std::string OpCode::Str() const
|
||||
{FLOAT64_STORE, "FLOAT64_STORE"},
|
||||
{INT32_TO_FLOAT64, "INT32_TO_FLOAT64"},
|
||||
{FLOAT64_TO_INT32, "FLOAT64_TO_INT32"},
|
||||
{TAGGED_POINTER_TO_INT64, "TAGGED_POINTER_TO_INT64"},
|
||||
{BITCAST_INT64_TO_FLOAT64, "BITCAST_INT64_TO_FLOAT64"},
|
||||
{BITCAST_FLOAT64_TO_INT64, "BITCAST_FLOAT64_TO_INT64"},
|
||||
{VALUE_SELECTOR_ANYVALUE, "VALUE_SELECTOR_ANYVALUE"},
|
||||
};
|
||||
if (strMap.count(this->op) > 0) {
|
||||
return strMap.at(this->op);
|
||||
if (strMap.count(op_) > 0) {
|
||||
return strMap.at(op_);
|
||||
}
|
||||
return "OP-" + std::to_string(this->op);
|
||||
return "OP-" + std::to_string(op_);
|
||||
}
|
||||
// 4 : 4 means that there are 4 args in total
|
||||
std::array<size_t, 4> OpCode::GetOpCodeNumInsArray(BitField bitfield) const
|
||||
{
|
||||
const size_t manyDepend = 2;
|
||||
auto properties = this->GetProperties();
|
||||
auto properties = GetProperties();
|
||||
auto stateProp = properties.statesIn;
|
||||
auto dependProp = properties.dependsIn;
|
||||
auto valueProp = properties.valuesIn;
|
||||
@@ -518,7 +531,7 @@ std::array<size_t, 4> OpCode::GetOpCodeNumInsArray(BitField bitfield) const
|
||||
|
||||
size_t OpCode::GetOpCodeNumIns(BitField bitfield) const
|
||||
{
|
||||
auto numInsArray = this->GetOpCodeNumInsArray(bitfield);
|
||||
auto numInsArray = GetOpCodeNumInsArray(bitfield);
|
||||
// 2 : 2 means the third element.
|
||||
// 3 : 3 means the fourth element.
|
||||
return numInsArray[0] + numInsArray[1] + numInsArray[2] + numInsArray[3];
|
||||
@@ -526,13 +539,13 @@ size_t OpCode::GetOpCodeNumIns(BitField bitfield) const
|
||||
|
||||
ValueCode OpCode::GetValueCode() const
|
||||
{
|
||||
return this->GetProperties().returnValue;
|
||||
return GetProperties().returnValue;
|
||||
}
|
||||
|
||||
ValueCode OpCode::GetInValueCode(BitField bitfield, size_t idx) const
|
||||
{
|
||||
auto numInsArray = this->GetOpCodeNumInsArray(bitfield);
|
||||
auto valueProp = this->GetProperties().valuesIn;
|
||||
auto numInsArray = GetOpCodeNumInsArray(bitfield);
|
||||
auto valueProp = GetProperties().valuesIn;
|
||||
idx -= numInsArray[0];
|
||||
idx -= numInsArray[1];
|
||||
ASSERT(valueProp.has_value());
|
||||
@@ -544,7 +557,7 @@ ValueCode OpCode::GetInValueCode(BitField bitfield, size_t idx) const
|
||||
|
||||
OpCode OpCode::GetInStateCode(size_t idx) const
|
||||
{
|
||||
auto stateProp = this->GetProperties().statesIn;
|
||||
auto stateProp = GetProperties().statesIn;
|
||||
ASSERT(stateProp.has_value());
|
||||
if (stateProp->second) {
|
||||
return stateProp->first.at(std::min(idx, stateProp->first.size() - 1));
|
||||
@@ -580,9 +593,9 @@ std::string ValueCodeToStr(ValueCode valueCode)
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckNullInput() const
|
||||
{
|
||||
const auto numIns = this->GetNumIns();
|
||||
const auto numIns = GetNumIns();
|
||||
for (size_t idx = 0; idx < numIns; idx++) {
|
||||
if (this->IsInGateNull(idx)) {
|
||||
if (IsInGateNull(idx)) {
|
||||
return std::make_pair("In list contains null", idx);
|
||||
}
|
||||
}
|
||||
@@ -591,14 +604,14 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckNullInput() const
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckStateInput() const
|
||||
{
|
||||
const auto numInsArray = this->GetOpCode().GetOpCodeNumInsArray(this->GetBitField());
|
||||
const auto numInsArray = GetOpCode().GetOpCodeNumInsArray(GetBitField());
|
||||
size_t stateStart = 0;
|
||||
size_t stateEnd = numInsArray[0];
|
||||
for (size_t idx = stateStart; idx < stateEnd; idx++) {
|
||||
auto stateProp = this->GetOpCode().GetProperties().statesIn;
|
||||
auto stateProp = GetOpCode().GetProperties().statesIn;
|
||||
ASSERT(stateProp.has_value());
|
||||
auto expectedIn = this->GetOpCode().GetInStateCode(idx);
|
||||
auto actualIn = this->GetInGateConst(idx)->GetOpCode();
|
||||
auto expectedIn = GetOpCode().GetInStateCode(idx);
|
||||
auto actualIn = GetInGateConst(idx)->GetOpCode();
|
||||
if (expectedIn == OpCode::NOP) { // general
|
||||
if (!actualIn.IsGeneralState()) {
|
||||
return std::make_pair(
|
||||
@@ -617,12 +630,12 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckStateInput() const
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckValueInput() const
|
||||
{
|
||||
const auto numInsArray = this->GetOpCode().GetOpCodeNumInsArray(this->GetBitField());
|
||||
const auto numInsArray = GetOpCode().GetOpCodeNumInsArray(GetBitField());
|
||||
size_t valueStart = numInsArray[0] + numInsArray[1];
|
||||
size_t valueEnd = numInsArray[0] + numInsArray[1] + numInsArray[2]; // 2 : 2 means the third element.
|
||||
for (size_t idx = valueStart; idx < valueEnd; idx++) {
|
||||
auto expectedIn = this->GetOpCode().GetInValueCode(this->GetBitField(), idx);
|
||||
auto actualIn = this->GetInGateConst(idx)->GetOpCode().GetValueCode();
|
||||
auto expectedIn = GetOpCode().GetInValueCode(GetBitField(), idx);
|
||||
auto actualIn = GetInGateConst(idx)->GetOpCode().GetValueCode();
|
||||
if ((expectedIn != actualIn) && (expectedIn != ANYVALUE)) {
|
||||
return std::make_pair("Value input does not match (expected: " + ValueCodeToStr(expectedIn) +
|
||||
" actual: " + ValueCodeToStr(actualIn) + ")",
|
||||
@@ -634,12 +647,12 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckValueInput() const
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckDependInput() const
|
||||
{
|
||||
const auto numInsArray = this->GetOpCode().GetOpCodeNumInsArray(this->GetBitField());
|
||||
const auto numInsArray = GetOpCode().GetOpCodeNumInsArray(GetBitField());
|
||||
size_t dependStart = numInsArray[0];
|
||||
size_t dependEnd = dependStart + numInsArray[1];
|
||||
for (size_t idx = dependStart; idx < dependEnd; idx++) {
|
||||
if (this->GetInGateConst(idx)->GetNumInsArray()[1] == 0 &&
|
||||
this->GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
|
||||
if (GetInGateConst(idx)->GetNumInsArray()[1] == 0 &&
|
||||
GetInGateConst(idx)->GetOpCode() != OpCode::DEPEND_ENTRY) {
|
||||
return std::make_pair("Depend input is side-effect free", idx);
|
||||
}
|
||||
}
|
||||
@@ -648,7 +661,7 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckDependInput() const
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckStateOutput() const
|
||||
{
|
||||
if (this->GetOpCode().IsState()) {
|
||||
if (GetOpCode().IsState()) {
|
||||
size_t cnt = 0;
|
||||
const Gate *curGate = this;
|
||||
if (!curGate->IsFirstOutNull()) {
|
||||
@@ -665,11 +678,11 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckStateOutput() const
|
||||
}
|
||||
size_t expected = 0;
|
||||
bool needCheck = true;
|
||||
if (this->GetOpCode().IsTerminalState()) {
|
||||
if (GetOpCode().IsTerminalState()) {
|
||||
expected = 0;
|
||||
} else if (this->GetOpCode() == OpCode::IF_BRANCH) {
|
||||
} else if (GetOpCode() == OpCode::IF_BRANCH) {
|
||||
expected = 2; // 2: expected number of state out branches
|
||||
} else if (this->GetOpCode() == OpCode::SWITCH_BRANCH) {
|
||||
} else if (GetOpCode() == OpCode::SWITCH_BRANCH) {
|
||||
needCheck = false;
|
||||
} else {
|
||||
expected = 1;
|
||||
@@ -686,7 +699,7 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckStateOutput() const
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckBranchOutput() const
|
||||
{
|
||||
std::map<std::pair<OpCode, BitField>, size_t> setOfOps;
|
||||
if (this->GetOpCode() == OpCode::IF_BRANCH || this->GetOpCode() == OpCode::SWITCH_BRANCH) {
|
||||
if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::SWITCH_BRANCH) {
|
||||
size_t cnt = 0;
|
||||
const Gate *curGate = this;
|
||||
if (!curGate->IsFirstOutNull()) {
|
||||
@@ -712,8 +725,8 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckBranchOutput() const
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckNOP() const
|
||||
{
|
||||
if (this->GetOpCode() == OpCode::NOP) {
|
||||
if (!this->IsFirstOutNull()) {
|
||||
if (GetOpCode() == OpCode::NOP) {
|
||||
if (!IsFirstOutNull()) {
|
||||
return std::make_pair("NOP gate used by other gates", -1);
|
||||
}
|
||||
}
|
||||
@@ -722,21 +735,21 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckNOP() const
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckSelector() const
|
||||
{
|
||||
if (this->GetOpCode() == OpCode::VALUE_SELECTOR_JS ||
|
||||
(OpCode::VALUE_SELECTOR_INT1 <= this->GetOpCode() && this->GetOpCode() <= OpCode::VALUE_SELECTOR_FLOAT64) ||
|
||||
this->GetOpCode() == OpCode::DEPEND_SELECTOR) {
|
||||
auto stateOp = this->GetInGateConst(0)->GetOpCode();
|
||||
if (GetOpCode() == OpCode::VALUE_SELECTOR_JS ||
|
||||
(OpCode::VALUE_SELECTOR_INT1 <= GetOpCode() && GetOpCode() <= OpCode::VALUE_SELECTOR_FLOAT64) ||
|
||||
GetOpCode() == OpCode::DEPEND_SELECTOR) {
|
||||
auto stateOp = GetInGateConst(0)->GetOpCode();
|
||||
if (stateOp == OpCode::MERGE || stateOp == OpCode::LOOP_BEGIN) {
|
||||
if (this->GetInGateConst(0)->GetNumIns() != this->GetNumIns() - 1) {
|
||||
if (this->GetOpCode() == OpCode::DEPEND_SELECTOR) {
|
||||
if (GetInGateConst(0)->GetNumIns() != GetNumIns() - 1) {
|
||||
if (GetOpCode() == OpCode::DEPEND_SELECTOR) {
|
||||
return std::make_pair("Number of depend flows does not match control flows (expected:" +
|
||||
std::to_string(this->GetInGateConst(0)->GetNumIns()) +
|
||||
" actual:" + std::to_string(this->GetNumIns() - 1) + ")",
|
||||
std::to_string(GetInGateConst(0)->GetNumIns()) +
|
||||
" actual:" + std::to_string(GetNumIns() - 1) + ")",
|
||||
-1);
|
||||
} else {
|
||||
return std::make_pair("Number of data flows does not match control flows (expected:" +
|
||||
std::to_string(this->GetInGateConst(0)->GetNumIns()) +
|
||||
" actual:" + std::to_string(this->GetNumIns() - 1) + ")",
|
||||
std::to_string(GetInGateConst(0)->GetNumIns()) +
|
||||
" actual:" + std::to_string(GetNumIns() - 1) + ")",
|
||||
-1);
|
||||
}
|
||||
}
|
||||
@@ -750,8 +763,8 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckSelector() const
|
||||
|
||||
std::optional<std::pair<std::string, size_t>> Gate::CheckRelay() const
|
||||
{
|
||||
if (this->GetOpCode() == OpCode::DEPEND_RELAY) {
|
||||
auto stateOp = this->GetInGateConst(0)->GetOpCode();
|
||||
if (GetOpCode() == OpCode::DEPEND_RELAY) {
|
||||
auto stateOp = GetInGateConst(0)->GetOpCode();
|
||||
if (!(stateOp == OpCode::IF_TRUE || stateOp == OpCode::IF_FALSE || stateOp == OpCode::SWITCH_CASE ||
|
||||
stateOp == OpCode::DEFAULT_CASE)) {
|
||||
return std::make_pair(
|
||||
@@ -766,19 +779,19 @@ std::optional<std::pair<std::string, size_t>> Gate::CheckRelay() const
|
||||
std::optional<std::pair<std::string, size_t>> Gate::SpecialCheck() const
|
||||
{
|
||||
{
|
||||
auto ret = this->CheckNOP();
|
||||
auto ret = CheckNOP();
|
||||
if (ret.has_value()) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
{
|
||||
auto ret = this->CheckSelector();
|
||||
auto ret = CheckSelector();
|
||||
if (ret.has_value()) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
{
|
||||
auto ret = this->CheckRelay();
|
||||
auto ret = CheckRelay();
|
||||
if (ret.has_value()) {
|
||||
return ret;
|
||||
}
|
||||
@@ -792,49 +805,49 @@ bool Gate::Verify() const
|
||||
size_t highlightIdx = -1;
|
||||
bool failed = false;
|
||||
{
|
||||
auto ret = this->CheckNullInput();
|
||||
auto ret = CheckNullInput();
|
||||
if (ret.has_value()) {
|
||||
failed = true;
|
||||
std::tie(errorString, highlightIdx) = ret.value();
|
||||
}
|
||||
}
|
||||
if (!failed) {
|
||||
auto ret = this->CheckStateInput();
|
||||
auto ret = CheckStateInput();
|
||||
if (ret.has_value()) {
|
||||
failed = true;
|
||||
std::tie(errorString, highlightIdx) = ret.value();
|
||||
}
|
||||
}
|
||||
if (!failed) {
|
||||
auto ret = this->CheckValueInput();
|
||||
auto ret = CheckValueInput();
|
||||
if (ret.has_value()) {
|
||||
failed = true;
|
||||
std::tie(errorString, highlightIdx) = ret.value();
|
||||
}
|
||||
}
|
||||
if (!failed) {
|
||||
auto ret = this->CheckDependInput();
|
||||
auto ret = CheckDependInput();
|
||||
if (ret.has_value()) {
|
||||
failed = true;
|
||||
std::tie(errorString, highlightIdx) = ret.value();
|
||||
}
|
||||
}
|
||||
if (!failed) {
|
||||
auto ret = this->CheckStateOutput();
|
||||
auto ret = CheckStateOutput();
|
||||
if (ret.has_value()) {
|
||||
failed = true;
|
||||
std::tie(errorString, highlightIdx) = ret.value();
|
||||
}
|
||||
}
|
||||
if (!failed) {
|
||||
auto ret = this->CheckBranchOutput();
|
||||
auto ret = CheckBranchOutput();
|
||||
if (ret.has_value()) {
|
||||
failed = true;
|
||||
std::tie(errorString, highlightIdx) = ret.value();
|
||||
}
|
||||
}
|
||||
if (!failed) {
|
||||
auto ret = this->SpecialCheck();
|
||||
auto ret = SpecialCheck();
|
||||
if (ret.has_value()) {
|
||||
failed = true;
|
||||
std::tie(errorString, highlightIdx) = ret.value();
|
||||
@@ -842,7 +855,7 @@ bool Gate::Verify() const
|
||||
}
|
||||
if (failed) {
|
||||
std::cerr << "[Verifier][Error] Gate level input list schema verify failed" << std::endl;
|
||||
this->Print(true, highlightIdx);
|
||||
Print(true, highlightIdx);
|
||||
std::cerr << "Note: " << errorString << std::endl;
|
||||
}
|
||||
return !failed;
|
||||
@@ -869,6 +882,15 @@ ValueCode PtrValueCode()
|
||||
#endif
|
||||
}
|
||||
|
||||
ValueCode ArchRelatePtrValueCode(const char *triple)
|
||||
{
|
||||
if (triple == TripleConst::GetLLVMArm32Triple()) {
|
||||
return ValueCode::INT32;
|
||||
} else {
|
||||
return ValueCode::INT64;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetValueBits(ValueCode valueCode)
|
||||
{
|
||||
switch (valueCode) {
|
||||
@@ -900,127 +922,127 @@ size_t GetOpCodeNumIns(OpCode opcode, BitField bitfield)
|
||||
|
||||
void Out::SetNextOut(const Out *ptr)
|
||||
{
|
||||
this->nextOut =
|
||||
nextOut_ =
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
static_cast<AddrShift>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
|
||||
static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
|
||||
}
|
||||
|
||||
Out *Out::GetNextOut()
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + this->nextOut);
|
||||
return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + nextOut_);
|
||||
}
|
||||
|
||||
const Out *Out::GetNextOutConst() const
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + this->nextOut);
|
||||
return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + nextOut_);
|
||||
}
|
||||
|
||||
void Out::SetPrevOut(const Out *ptr)
|
||||
{
|
||||
this->prevOut =
|
||||
prevOut_ =
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
static_cast<AddrShift>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
|
||||
static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
|
||||
}
|
||||
|
||||
Out *Out::GetPrevOut()
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + this->prevOut);
|
||||
return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + prevOut_);
|
||||
}
|
||||
|
||||
const Out *Out::GetPrevOutConst() const
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + this->prevOut);
|
||||
return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + prevOut_);
|
||||
}
|
||||
|
||||
void Out::SetIndex(OutIdx idx)
|
||||
{
|
||||
this->idx = idx;
|
||||
idx_ = idx;
|
||||
}
|
||||
|
||||
OutIdx Out::GetIndex() const
|
||||
{
|
||||
return this->idx;
|
||||
return idx_;
|
||||
}
|
||||
|
||||
Gate *Out::GetGate()
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<Gate *>(&this[this->idx + 1]);
|
||||
return reinterpret_cast<Gate *>(&this[idx_ + 1]);
|
||||
}
|
||||
|
||||
const Gate *Out::GetGateConst() const
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<const Gate *>(&this[this->idx + 1]);
|
||||
return reinterpret_cast<const Gate *>(&this[idx_ + 1]);
|
||||
}
|
||||
|
||||
void Out::SetPrevOutNull()
|
||||
{
|
||||
this->prevOut = 0;
|
||||
prevOut_ = 0;
|
||||
}
|
||||
|
||||
bool Out::IsPrevOutNull() const
|
||||
{
|
||||
return this->prevOut == 0;
|
||||
return prevOut_ == 0;
|
||||
}
|
||||
|
||||
void Out::SetNextOutNull()
|
||||
{
|
||||
this->nextOut = 0;
|
||||
nextOut_ = 0;
|
||||
}
|
||||
|
||||
bool Out::IsNextOutNull() const
|
||||
{
|
||||
return this->nextOut == 0;
|
||||
return nextOut_ == 0;
|
||||
}
|
||||
|
||||
void In::SetGate(const Gate *ptr)
|
||||
{
|
||||
this->gatePtr =
|
||||
gatePtr_ =
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
static_cast<AddrShift>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
|
||||
static_cast<GateRef>((reinterpret_cast<const uint8_t *>(ptr)) - (reinterpret_cast<const uint8_t *>(this)));
|
||||
}
|
||||
|
||||
Gate *In::GetGate()
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + this->gatePtr);
|
||||
return reinterpret_cast<Gate *>((reinterpret_cast<uint8_t *>(this)) + gatePtr_);
|
||||
}
|
||||
|
||||
const Gate *In::GetGateConst() const
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + this->gatePtr);
|
||||
return reinterpret_cast<const Gate *>((reinterpret_cast<const uint8_t *>(this)) + gatePtr_);
|
||||
}
|
||||
|
||||
void In::SetGateNull()
|
||||
{
|
||||
this->gatePtr = 0;
|
||||
gatePtr_ = 0;
|
||||
}
|
||||
|
||||
bool In::IsGateNull() const
|
||||
{
|
||||
return this->gatePtr == 0;
|
||||
return gatePtr_ == 0;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
|
||||
Gate::Gate(GateId id, OpCode opcode, BitField bitfield, Gate *inList[], TypeCode type, MarkCode mark)
|
||||
: id(id), opcode(opcode), type(type), stamp(1), mark(mark), bitfield(bitfield), firstOut(0)
|
||||
: id_(id), opcode_(opcode), type_(type), stamp_(1), mark_(mark), bitfield_(bitfield), firstOut_(0)
|
||||
{
|
||||
auto numIns = this->GetNumIns();
|
||||
auto numIns = GetNumIns();
|
||||
for (size_t idx = 0; idx < numIns; idx++) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
auto in = inList[idx];
|
||||
if (in == nullptr) {
|
||||
this->GetIn(idx)->SetGateNull();
|
||||
GetIn(idx)->SetGateNull();
|
||||
} else {
|
||||
this->NewIn(idx, in);
|
||||
NewIn(idx, in);
|
||||
}
|
||||
auto curOut = this->GetOut(idx);
|
||||
auto curOut = GetOut(idx);
|
||||
curOut->SetIndex(idx);
|
||||
}
|
||||
}
|
||||
@@ -1032,7 +1054,7 @@ size_t Gate::GetOutListSize(size_t numIns)
|
||||
|
||||
size_t Gate::GetOutListSize() const
|
||||
{
|
||||
return Gate::GetOutListSize(this->GetNumIns());
|
||||
return Gate::GetOutListSize(GetNumIns());
|
||||
}
|
||||
|
||||
size_t Gate::GetInListSize(size_t numIns)
|
||||
@@ -1042,7 +1064,7 @@ size_t Gate::GetInListSize(size_t numIns)
|
||||
|
||||
size_t Gate::GetInListSize() const
|
||||
{
|
||||
return Gate::GetInListSize(this->GetNumIns());
|
||||
return Gate::GetInListSize(GetNumIns());
|
||||
}
|
||||
|
||||
size_t Gate::GetGateSize(size_t numIns)
|
||||
@@ -1052,13 +1074,13 @@ size_t Gate::GetGateSize(size_t numIns)
|
||||
|
||||
size_t Gate::GetGateSize() const
|
||||
{
|
||||
return Gate::GetGateSize(this->GetNumIns());
|
||||
return Gate::GetGateSize(GetNumIns());
|
||||
}
|
||||
|
||||
void Gate::NewIn(size_t idx, Gate *in)
|
||||
{
|
||||
this->GetIn(idx)->SetGate(in);
|
||||
auto curOut = this->GetOut(idx);
|
||||
GetIn(idx)->SetGate(in);
|
||||
auto curOut = GetOut(idx);
|
||||
if (in->IsFirstOutNull()) {
|
||||
curOut->SetNextOutNull();
|
||||
} else {
|
||||
@@ -1071,33 +1093,33 @@ void Gate::NewIn(size_t idx, Gate *in)
|
||||
|
||||
void Gate::ModifyIn(size_t idx, Gate *in)
|
||||
{
|
||||
this->DeleteIn(idx);
|
||||
this->NewIn(idx, in);
|
||||
DeleteIn(idx);
|
||||
NewIn(idx, in);
|
||||
}
|
||||
|
||||
void Gate::DeleteIn(size_t idx)
|
||||
{
|
||||
if (!this->GetOut(idx)->IsNextOutNull() && !this->GetOut(idx)->IsPrevOutNull()) {
|
||||
this->GetOut(idx)->GetPrevOut()->SetNextOut(this->GetOut(idx)->GetNextOut());
|
||||
this->GetOut(idx)->GetNextOut()->SetPrevOut(this->GetOut(idx)->GetPrevOut());
|
||||
} else if (this->GetOut(idx)->IsNextOutNull() && !this->GetOut(idx)->IsPrevOutNull()) {
|
||||
this->GetOut(idx)->GetPrevOut()->SetNextOutNull();
|
||||
} else if (!this->GetOut(idx)->IsNextOutNull()) { // then this->GetOut(idx)->IsPrevOutNull() is true
|
||||
this->GetIn(idx)->GetGate()->SetFirstOut(this->GetOut(idx)->GetNextOut());
|
||||
this->GetOut(idx)->GetNextOut()->SetPrevOutNull();
|
||||
if (!GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
|
||||
GetOut(idx)->GetPrevOut()->SetNextOut(GetOut(idx)->GetNextOut());
|
||||
GetOut(idx)->GetNextOut()->SetPrevOut(GetOut(idx)->GetPrevOut());
|
||||
} else if (GetOut(idx)->IsNextOutNull() && !GetOut(idx)->IsPrevOutNull()) {
|
||||
GetOut(idx)->GetPrevOut()->SetNextOutNull();
|
||||
} else if (!GetOut(idx)->IsNextOutNull()) { // then GetOut(idx)->IsPrevOutNull() is true
|
||||
GetIn(idx)->GetGate()->SetFirstOut(GetOut(idx)->GetNextOut());
|
||||
GetOut(idx)->GetNextOut()->SetPrevOutNull();
|
||||
} else { // only this out now
|
||||
this->GetIn(idx)->GetGate()->SetFirstOutNull();
|
||||
GetIn(idx)->GetGate()->SetFirstOutNull();
|
||||
}
|
||||
this->GetIn(idx)->SetGateNull();
|
||||
GetIn(idx)->SetGateNull();
|
||||
}
|
||||
|
||||
void Gate::DeleteGate()
|
||||
{
|
||||
auto numIns = this->GetNumIns();
|
||||
auto numIns = GetNumIns();
|
||||
for (size_t idx = 0; idx < numIns; idx++) {
|
||||
this->DeleteIn(idx);
|
||||
DeleteIn(idx);
|
||||
}
|
||||
this->SetOpCode(OpCode(OpCode::NOP));
|
||||
SetOpCode(OpCode(OpCode::NOP));
|
||||
}
|
||||
|
||||
Out *Gate::GetOut(size_t idx)
|
||||
@@ -1109,38 +1131,38 @@ Out *Gate::GetOut(size_t idx)
|
||||
Out *Gate::GetFirstOut()
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + this->firstOut);
|
||||
return reinterpret_cast<Out *>((reinterpret_cast<uint8_t *>(this)) + firstOut_);
|
||||
}
|
||||
|
||||
const Out *Gate::GetFirstOutConst() const
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + this->firstOut);
|
||||
return reinterpret_cast<const Out *>((reinterpret_cast<const uint8_t *>(this)) + firstOut_);
|
||||
}
|
||||
|
||||
void Gate::SetFirstOutNull()
|
||||
{
|
||||
this->firstOut = 0;
|
||||
firstOut_ = 0;
|
||||
}
|
||||
|
||||
bool Gate::IsFirstOutNull() const
|
||||
{
|
||||
return this->firstOut == 0;
|
||||
return firstOut_ == 0;
|
||||
}
|
||||
|
||||
void Gate::SetFirstOut(const Out *firstOut)
|
||||
{
|
||||
this->firstOut =
|
||||
firstOut_ =
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
static_cast<AddrShift>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
|
||||
static_cast<GateRef>(reinterpret_cast<const uint8_t *>(firstOut) - reinterpret_cast<const uint8_t *>(this));
|
||||
}
|
||||
|
||||
In *Gate::GetIn(size_t idx)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (idx >= this->GetNumIns()) {
|
||||
if (idx >= GetNumIns()) {
|
||||
std::cerr << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")" << std::endl;
|
||||
this->Print();
|
||||
Print();
|
||||
ASSERT(false);
|
||||
}
|
||||
#endif
|
||||
@@ -1151,9 +1173,9 @@ In *Gate::GetIn(size_t idx)
|
||||
const In *Gate::GetInConst(size_t idx) const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (idx >= this->GetNumIns()) {
|
||||
if (idx >= GetNumIns()) {
|
||||
std::cerr << std::dec << "Gate In access out-of-bound! (idx=" << idx << ")" << std::endl;
|
||||
this->Print();
|
||||
Print();
|
||||
ASSERT(false);
|
||||
}
|
||||
#endif
|
||||
@@ -1163,72 +1185,82 @@ const In *Gate::GetInConst(size_t idx) const
|
||||
|
||||
Gate *Gate::GetInGate(size_t idx)
|
||||
{
|
||||
return this->GetIn(idx)->GetGate();
|
||||
return GetIn(idx)->GetGate();
|
||||
}
|
||||
|
||||
const Gate *Gate::GetInGateConst(size_t idx) const
|
||||
{
|
||||
return this->GetInConst(idx)->GetGateConst();
|
||||
return GetInConst(idx)->GetGateConst();
|
||||
}
|
||||
|
||||
bool Gate::IsInGateNull(size_t idx) const
|
||||
{
|
||||
return this->GetInConst(idx)->IsGateNull();
|
||||
return GetInConst(idx)->IsGateNull();
|
||||
}
|
||||
|
||||
GateId Gate::GetId() const
|
||||
{
|
||||
return id;
|
||||
return id_;
|
||||
}
|
||||
|
||||
OpCode Gate::GetOpCode() const
|
||||
{
|
||||
return this->opcode;
|
||||
return opcode_;
|
||||
}
|
||||
|
||||
void Gate::SetOpCode(OpCode opcode)
|
||||
{
|
||||
this->opcode = opcode;
|
||||
opcode_ = opcode;
|
||||
}
|
||||
|
||||
TypeCode Gate::GetTypeCode() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
void Gate::SetTypeCode(TypeCode type)
|
||||
{
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
size_t Gate::GetNumIns() const
|
||||
{
|
||||
return GetOpCodeNumIns(this->GetOpCode(), this->GetBitField());
|
||||
return GetOpCodeNumIns(GetOpCode(), GetBitField());
|
||||
}
|
||||
|
||||
std::array<size_t, 4> Gate::GetNumInsArray() const // 4 : 4 means that there are 4 args.
|
||||
{
|
||||
return this->GetOpCode().GetOpCodeNumInsArray(this->GetBitField());
|
||||
return GetOpCode().GetOpCodeNumInsArray(GetBitField());
|
||||
}
|
||||
|
||||
BitField Gate::GetBitField() const
|
||||
{
|
||||
return this->bitfield;
|
||||
return bitfield_;
|
||||
}
|
||||
|
||||
void Gate::SetBitField(BitField bitfield)
|
||||
{
|
||||
this->bitfield = bitfield;
|
||||
bitfield_ = bitfield;
|
||||
}
|
||||
|
||||
void Gate::Print(bool inListPreview, size_t highlightIdx) const
|
||||
{
|
||||
if (this->GetOpCode() != OpCode::NOP) {
|
||||
if (GetOpCode() != OpCode::NOP) {
|
||||
std::cerr << std::dec << "("
|
||||
<< "id=" << this->id << ", "
|
||||
<< "op=" << this->GetOpCode().Str() << ", "
|
||||
<< "bitfield=" << std::to_string(this->bitfield) << ", "
|
||||
<< "type=" << static_cast<uint32_t>(this->type) << ", "
|
||||
<< "stamp=" << static_cast<uint32_t>(this->stamp) << ", "
|
||||
<< "mark=" << static_cast<uint32_t>(this->mark) << ", ";
|
||||
<< "id=" << id_ << ", "
|
||||
<< "op=" << GetOpCode().Str() << ", "
|
||||
<< "bitfield=" << std::to_string(bitfield_) << ", "
|
||||
<< "type=" << static_cast<uint32_t>(type_) << ", "
|
||||
<< "stamp=" << static_cast<uint32_t>(stamp_) << ", "
|
||||
<< "mark=" << static_cast<uint32_t>(mark_) << ", ";
|
||||
std::cerr << "in="
|
||||
<< "[";
|
||||
for (size_t idx = 0; idx < this->GetNumIns(); idx++) {
|
||||
for (size_t idx = 0; idx < GetNumIns(); idx++) {
|
||||
std::cerr << std::dec << ((idx == 0) ? "" : " ") << ((idx == highlightIdx) ? "\033[4;31m" : "")
|
||||
<< ((this->IsInGateNull(idx)
|
||||
<< ((IsInGateNull(idx)
|
||||
? "N"
|
||||
: (std::to_string(this->GetInGateConst(idx)->GetId()) +
|
||||
(inListPreview ? std::string(":" + this->GetInGateConst(idx)->GetOpCode().Str())
|
||||
: (std::to_string(GetInGateConst(idx)->GetId()) +
|
||||
(inListPreview ? std::string(":" + GetInGateConst(idx)->GetOpCode().Str())
|
||||
: std::string("")))))
|
||||
<< ((idx == highlightIdx) ? "\033[0m" : "");
|
||||
}
|
||||
@@ -1236,8 +1268,8 @@ void Gate::Print(bool inListPreview, size_t highlightIdx) const
|
||||
<< ", ";
|
||||
std::cerr << "out="
|
||||
<< "[";
|
||||
if (!this->IsFirstOutNull()) {
|
||||
const Out *curOut = this->GetFirstOutConst();
|
||||
if (!IsFirstOutNull()) {
|
||||
const Out *curOut = GetFirstOutConst();
|
||||
std::cerr << std::dec << ""
|
||||
<< std::to_string(curOut->GetGateConst()->GetId()) +
|
||||
(inListPreview ? std::string(":" + curOut->GetGateConst()->GetOpCode().Str()) : std::string(""));
|
||||
@@ -1256,79 +1288,75 @@ void Gate::Print(bool inListPreview, size_t highlightIdx) const
|
||||
|
||||
MarkCode Gate::GetMark(TimeStamp stamp) const
|
||||
{
|
||||
return (this->stamp == stamp) ? this->mark : MarkCode::EMPTY;
|
||||
return (stamp_ == stamp) ? mark_ : MarkCode::EMPTY;
|
||||
}
|
||||
|
||||
void Gate::SetMark(MarkCode mark, TimeStamp stamp)
|
||||
{
|
||||
this->stamp = stamp;
|
||||
this->mark = mark;
|
||||
}
|
||||
|
||||
TypeCode Gate::GetTypeCode() const
|
||||
{
|
||||
return type;
|
||||
stamp_ = stamp;
|
||||
mark_ = mark;
|
||||
}
|
||||
|
||||
bool OpCode::IsRoot() const
|
||||
{
|
||||
return (this->GetProperties().states == OpCode::CIRCUIT_ROOT) || (this->op == OpCode::CIRCUIT_ROOT);
|
||||
return (GetProperties().states == OpCode::CIRCUIT_ROOT) || (op_ == OpCode::CIRCUIT_ROOT);
|
||||
}
|
||||
|
||||
bool OpCode::IsProlog() const
|
||||
{
|
||||
return (this->GetProperties().states == OpCode::ARG_LIST);
|
||||
return (GetProperties().states == OpCode::ARG_LIST);
|
||||
}
|
||||
|
||||
bool OpCode::IsFixed() const
|
||||
{
|
||||
return (this->GetOpCodeNumInsArray(1)[0] > 0) &&
|
||||
((this->GetValueCode() != NOVALUE) ||
|
||||
((this->GetOpCodeNumInsArray(1)[1] > 0) && (this->GetOpCodeNumInsArray(1)[2] == 0)));
|
||||
return (GetOpCodeNumInsArray(1)[0] > 0) &&
|
||||
((GetValueCode() != NOVALUE) ||
|
||||
((GetOpCodeNumInsArray(1)[1] > 0) && (GetOpCodeNumInsArray(1)[2] == 0) &&
|
||||
(GetOpCodeNumInsArray(1)[3] == 0)));
|
||||
}
|
||||
|
||||
bool OpCode::IsSchedulable() const
|
||||
{
|
||||
return (this->op != OpCode::NOP) && (!this->IsProlog()) && (!this->IsRoot()) && (!this->IsFixed()) &&
|
||||
(this->GetOpCodeNumInsArray(1)[0] == 0);
|
||||
return (op_ != OpCode::NOP) && (!IsProlog()) && (!IsRoot()) && (!IsFixed()) &&
|
||||
(GetOpCodeNumInsArray(1)[0] == 0);
|
||||
}
|
||||
|
||||
bool OpCode::IsState() const
|
||||
{
|
||||
return (this->op != OpCode::NOP) && (!this->IsProlog()) && (!this->IsRoot()) && (!this->IsFixed()) &&
|
||||
(this->GetOpCodeNumInsArray(1)[0] > 0);
|
||||
return (op_ != OpCode::NOP) && (!IsProlog()) && (!IsRoot()) && (!IsFixed()) &&
|
||||
(GetOpCodeNumInsArray(1)[0] > 0);
|
||||
}
|
||||
|
||||
bool OpCode::IsGeneralState() const
|
||||
{
|
||||
return ((this->op == OpCode::IF_TRUE) || (this->op == OpCode::IF_FALSE) || (this->op == OpCode::SWITCH_CASE) ||
|
||||
(this->op == OpCode::DEFAULT_CASE) || (this->op == OpCode::MERGE) || (this->op == OpCode::LOOP_BEGIN) ||
|
||||
(this->op == OpCode::ORDINARY_BLOCK) || (this->op == OpCode::STATE_ENTRY));
|
||||
return ((op_ == OpCode::IF_TRUE) || (op_ == OpCode::IF_FALSE) || (op_ == OpCode::SWITCH_CASE) ||
|
||||
(op_ == OpCode::DEFAULT_CASE) || (op_ == OpCode::MERGE) || (op_ == OpCode::LOOP_BEGIN) ||
|
||||
(op_ == OpCode::ORDINARY_BLOCK) || (op_ == OpCode::STATE_ENTRY));
|
||||
}
|
||||
|
||||
bool OpCode::IsTerminalState() const
|
||||
{
|
||||
return ((this->op == OpCode::RETURN) || (this->op == OpCode::THROW));
|
||||
return ((op_ == OpCode::RETURN) || (op_ == OpCode::THROW) || (op_ == OpCode::RETURN_VOID));
|
||||
}
|
||||
|
||||
bool OpCode::IsCFGMerge() const
|
||||
{
|
||||
return (this->op == OpCode::MERGE) || (this->op == OpCode::LOOP_BEGIN);
|
||||
return (op_ == OpCode::MERGE) || (op_ == OpCode::LOOP_BEGIN);
|
||||
}
|
||||
|
||||
bool OpCode::IsControlCase() const
|
||||
{
|
||||
return (this->op == OpCode::IF_BRANCH) || (this->op == OpCode::SWITCH_BRANCH) || (this->op == OpCode::IF_TRUE) ||
|
||||
(this->op == OpCode::IF_FALSE) || (this->op == OpCode::SWITCH_CASE) || (this->op == OpCode::DEFAULT_CASE);
|
||||
return (op_ == OpCode::IF_BRANCH) || (op_ == OpCode::SWITCH_BRANCH) || (op_ == OpCode::IF_TRUE) ||
|
||||
(op_ == OpCode::IF_FALSE) || (op_ == OpCode::SWITCH_CASE) || (op_ == OpCode::DEFAULT_CASE);
|
||||
}
|
||||
|
||||
bool OpCode::IsLoopHead() const
|
||||
{
|
||||
return (this->op == OpCode::LOOP_BEGIN);
|
||||
return (op_ == OpCode::LOOP_BEGIN);
|
||||
}
|
||||
|
||||
bool OpCode::IsNop() const
|
||||
{
|
||||
return (this->op == OpCode::NOP);
|
||||
return (op_ == OpCode::NOP);
|
||||
}
|
||||
} // namespace kungfu
|
||||
+23
-17
@@ -30,11 +30,12 @@
|
||||
#include "ecmascript/compiler/type.h"
|
||||
|
||||
namespace kungfu {
|
||||
using GateRef = int32_t; // for external users
|
||||
using GateId = uint32_t;
|
||||
using GateOp = uint8_t;
|
||||
using GateMark = uint8_t;
|
||||
using TimeStamp = uint8_t;
|
||||
using AddrShift = int32_t;
|
||||
using GateRef = int32_t;
|
||||
using BitField = uint64_t;
|
||||
using OutIdx = uint32_t;
|
||||
class Gate;
|
||||
@@ -49,7 +50,6 @@ enum ValueCode {
|
||||
INT64,
|
||||
FLOAT32,
|
||||
FLOAT64,
|
||||
TAGGED_POINTER,
|
||||
};
|
||||
|
||||
std::string ValueCodeToStr(ValueCode valueCode);
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
ALLOCA_LIST,
|
||||
ARG_LIST,
|
||||
RETURN,
|
||||
RETURN_VOID,
|
||||
THROW,
|
||||
ORDINARY_BLOCK,
|
||||
IF_BRANCH,
|
||||
@@ -90,6 +91,7 @@ public:
|
||||
VALUE_SELECTOR_INT64,
|
||||
VALUE_SELECTOR_FLOAT32,
|
||||
VALUE_SELECTOR_FLOAT64,
|
||||
VALUE_SELECTOR_ANYVALUE,
|
||||
DEPEND_SELECTOR,
|
||||
DEPEND_RELAY,
|
||||
DEPEND_AND,
|
||||
@@ -130,6 +132,7 @@ public:
|
||||
FLOAT32_CALL,
|
||||
FLOAT64_CALL,
|
||||
TAGGED_POINTER_CALL,
|
||||
ANYVALUE_CALL,
|
||||
ALLOCA,
|
||||
INT1_ARG,
|
||||
INT8_ARG,
|
||||
@@ -231,16 +234,17 @@ public:
|
||||
FLOAT64_STORE,
|
||||
INT32_TO_FLOAT64,
|
||||
FLOAT64_TO_INT32,
|
||||
TAGGED_POINTER_TO_INT64,
|
||||
BITCAST_INT64_TO_FLOAT64,
|
||||
BITCAST_FLOAT64_TO_INT64,
|
||||
TAG64_TO_INT1,
|
||||
};
|
||||
|
||||
OpCode() = default;
|
||||
explicit constexpr OpCode(Op op) : op(op) {}
|
||||
explicit constexpr OpCode(Op op) : op_(op) {}
|
||||
operator Op() const
|
||||
{
|
||||
return this->op;
|
||||
return op_;
|
||||
}
|
||||
explicit operator bool() const = delete;
|
||||
[[nodiscard]] Properties GetProperties() const;
|
||||
@@ -264,7 +268,7 @@ public:
|
||||
~OpCode() = default;
|
||||
|
||||
private:
|
||||
Op op;
|
||||
Op op_;
|
||||
};
|
||||
|
||||
struct Properties {
|
||||
@@ -283,6 +287,7 @@ enum MarkCode : GateMark {
|
||||
|
||||
ValueCode JSValueCode();
|
||||
ValueCode PtrValueCode();
|
||||
ValueCode ArchRelatePtrValueCode(const char *triple);
|
||||
size_t GetValueBits(ValueCode valueCode);
|
||||
|
||||
class Out {
|
||||
@@ -305,9 +310,9 @@ public:
|
||||
~Out() = default;
|
||||
|
||||
private:
|
||||
OutIdx idx;
|
||||
AddrShift nextOut;
|
||||
AddrShift prevOut;
|
||||
OutIdx idx_;
|
||||
GateRef nextOut_;
|
||||
GateRef prevOut_;
|
||||
};
|
||||
|
||||
class In {
|
||||
@@ -321,7 +326,7 @@ public:
|
||||
~In() = default;
|
||||
|
||||
private:
|
||||
AddrShift gatePtr;
|
||||
GateRef gatePtr_;
|
||||
};
|
||||
|
||||
class Gate {
|
||||
@@ -356,6 +361,8 @@ public:
|
||||
[[nodiscard]] bool IsInGateNull(size_t idx) const;
|
||||
[[nodiscard]] OpCode GetOpCode() const;
|
||||
void SetOpCode(OpCode opcode);
|
||||
[[nodiscard]] TypeCode GetTypeCode() const;
|
||||
void SetTypeCode(TypeCode type);
|
||||
[[nodiscard]] GateId GetId() const;
|
||||
[[nodiscard]] size_t GetNumIns() const;
|
||||
[[nodiscard]] std::array<size_t, 4> GetNumInsArray() const;
|
||||
@@ -376,7 +383,6 @@ public:
|
||||
[[nodiscard]] bool Verify() const;
|
||||
[[nodiscard]] MarkCode GetMark(TimeStamp stamp) const;
|
||||
void SetMark(MarkCode mark, TimeStamp stamp);
|
||||
TypeCode GetTypeCode() const;
|
||||
~Gate() = default;
|
||||
|
||||
private:
|
||||
@@ -384,13 +390,13 @@ private:
|
||||
// out(2)
|
||||
// out(1)
|
||||
// out(0)
|
||||
GateId id;
|
||||
OpCode opcode;
|
||||
TypeCode type;
|
||||
TimeStamp stamp;
|
||||
MarkCode mark;
|
||||
BitField bitfield;
|
||||
AddrShift firstOut;
|
||||
GateId id_;
|
||||
OpCode opcode_;
|
||||
TypeCode type_;
|
||||
TimeStamp stamp_;
|
||||
MarkCode mark_;
|
||||
BitField bitfield_;
|
||||
GateRef firstOut_;
|
||||
// in(0)
|
||||
// in(1)
|
||||
// in(2)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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/compiler/js_thread_offset_table.h"
|
||||
#include "ecmascript/compiler/triple.h"
|
||||
|
||||
namespace kungfu {
|
||||
using namespace panda::ecmascript;
|
||||
OffsetTable *OffsetTable::instance_ = nullptr;
|
||||
OffsetTable::OffsetTable(const char* triple)
|
||||
{
|
||||
if (triple == TripleConst::GetLLVMArm32Triple()) {
|
||||
offsetTable_ = {
|
||||
GLUE_EXCEPTION_OFFSET_32, GLUE_GLOBAL_CONSTANTS_OFFSET_32, GLUE_PROPERTIES_CACHE_OFFSET_32,
|
||||
GLUE_GLOBAL_STORAGE_OFFSET_32, GLUE_CURRENT_FRAME_OFFSET_32, GLUE_LAST_IFRAME_OFFSET_32,
|
||||
GLUE_RUNTIME_FUNCTIONS_OFFSET_32, GLUE_FASTSTUB_ENTRIES_OFFSET_32
|
||||
};
|
||||
} else if (triple == TripleConst::GetLLVMArm64Triple() || triple == TripleConst::GetLLVMAmd64Triple()) {
|
||||
offsetTable_ = {
|
||||
GLUE_EXCEPTION_OFFSET_64, GLUE_GLOBAL_CONSTANTS_OFFSET_64, GLUE_PROPERTIES_CACHE_OFFSET_64,
|
||||
GLUE_GLOBAL_STORAGE_OFFSET_64, GLUE_CURRENT_FRAME_OFFSET_64, GLUE_LAST_IFRAME_OFFSET_64,
|
||||
GLUE_RUNTIME_FUNCTIONS_OFFSET_64, GLUE_FASTSTUB_ENTRIES_OFFSET_64
|
||||
};
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
// static
|
||||
void OffsetTable::CreateInstance(const char* triple)
|
||||
{
|
||||
instance_ = new OffsetTable(triple);
|
||||
}
|
||||
// static
|
||||
void OffsetTable::Destroy()
|
||||
{
|
||||
if (instance_) {
|
||||
delete instance_;
|
||||
instance_ = nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace kungfu
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_COMPILER_JS_THREAD_OFFSET_TABLE_H
|
||||
#define ECMASCRIPT_COMPILER_JS_THREAD_OFFSET_TABLE_H
|
||||
|
||||
#include <array>
|
||||
#include "ecmascript/js_thread.h"
|
||||
|
||||
// this class only use in host compiling
|
||||
namespace kungfu {
|
||||
using JSThread = panda::ecmascript::JSThread;
|
||||
class OffsetTable {
|
||||
public:
|
||||
static void CreateInstance(const char* triple);
|
||||
static void Destroy();
|
||||
static OffsetTable *GetInstance()
|
||||
{
|
||||
ASSERT(instance_);
|
||||
return instance_;
|
||||
}
|
||||
|
||||
static uint32_t GetOffset(JSThread::GlueID id)
|
||||
{
|
||||
ASSERT(instance_);
|
||||
return instance_->offsetTable_[static_cast<size_t>(id)];
|
||||
}
|
||||
|
||||
private:
|
||||
explicit OffsetTable(const char* triple);
|
||||
~OffsetTable() = default;
|
||||
|
||||
static OffsetTable *instance_;
|
||||
std::array<uint32_t, static_cast<size_t>(JSThread::GlueID::NUMBER_OF_GLUE)> offsetTable_ {};
|
||||
|
||||
NO_COPY_SEMANTIC(OffsetTable);
|
||||
NO_MOVE_SEMANTIC(OffsetTable);
|
||||
};
|
||||
} // namespace kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_JS_THREAD_OFFSET_TABLE_H
|
||||
@@ -1,125 +0,0 @@
|
||||
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
|
||||
index 0e85afa82c7..43756892e40 100644
|
||||
--- a/llvm/CMakeLists.txt
|
||||
+++ b/llvm/CMakeLists.txt
|
||||
@@ -505,8 +505,15 @@ option(LLVM_BUILD_RUNTIME
|
||||
"Build the LLVM runtime libraries." ON)
|
||||
option(LLVM_BUILD_EXAMPLES
|
||||
"Build the LLVM example programs. If OFF, just generate build targets." OFF)
|
||||
+option(BUILD_ARK_GC_SUPPORT
|
||||
+ "ARK support GC. If ON, support GC." OFF)
|
||||
+if(BUILD_ARK_GC_SUPPORT)
|
||||
+ add_definitions(-DARK_GC_SUPPORT)
|
||||
+endif(BUILD_ARK_GC_SUPPORT)
|
||||
+
|
||||
option(LLVM_INCLUDE_EXAMPLES "Generate build targets for the LLVM examples" ON)
|
||||
|
||||
+
|
||||
if(LLVM_BUILD_EXAMPLES)
|
||||
add_definitions(-DBUILD_EXAMPLES)
|
||||
endif(LLVM_BUILD_EXAMPLES)
|
||||
diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
|
||||
index 1da20371caf..e0264827556 100644
|
||||
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
|
||||
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
|
||||
@@ -1168,6 +1168,25 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
else
|
||||
MFI.setOffsetAdjustment(-StackSize);
|
||||
}
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ // push marker
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call"))
|
||||
+ {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64i32 : X86::PUSH32i8))
|
||||
+ .addImm(marker)
|
||||
+ .setMIFlag(MachineInstr::FrameSetup);
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64i32 : X86::PUSH32i8))
|
||||
+ .addImm(marker)
|
||||
+ .setMIFlag(MachineInstr::FrameSetup);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
// For EH funclets, only allocate enough space for outgoing calls. Save the
|
||||
// NumBytes value that we would've used for the parent frame.
|
||||
@@ -1635,6 +1654,27 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
uint64_t SEHStackAllocAmt = NumBytes;
|
||||
|
||||
if (HasFP) {
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call"))
|
||||
+ {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+
|
||||
+ // pop marker
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
|
||||
+ MachineFramePtr)
|
||||
+ .setMIFlag(MachineInstr::FrameDestroy);
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ // pop thread.fp
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
|
||||
+ MachineFramePtr)
|
||||
+ .setMIFlag(MachineInstr::FrameDestroy);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
// Pop EBP.
|
||||
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
|
||||
MachineFramePtr)
|
||||
@@ -1993,8 +2033,33 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots(
|
||||
|
||||
if (hasFP(MF)) {
|
||||
// emitPrologue always spills frame register the first thing.
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call")) {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ SpillSlotOffset -= 3 * SlotSize; // add type and thread.fp
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ CalleeSavedFrameSize += (2 * SlotSize);
|
||||
+ } else {
|
||||
+ SpillSlotOffset -= 2 * SlotSize; // add type
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ CalleeSavedFrameSize += SlotSize;
|
||||
+ }
|
||||
+ } else {
|
||||
+ SpillSlotOffset -= SlotSize; // add type and thread.fp
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ }
|
||||
+#else
|
||||
SpillSlotOffset -= SlotSize;
|
||||
MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+#endif
|
||||
|
||||
// Since emitPrologue and emitEpilogue will handle spilling and restoring of
|
||||
// the frame register, we can delete it from CSI list and not have to worry
|
||||
diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h
|
||||
index 2103d6471ea..3fd89b0d9ee 100644
|
||||
--- a/llvm/lib/Target/X86/X86FrameLowering.h
|
||||
+++ b/llvm/lib/Target/X86/X86FrameLowering.h
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||
|
||||
+#define JS_ENTRY_FRAME_MARK 1
|
||||
+
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstrBuilder;
|
||||
@@ -0,0 +1,928 @@
|
||||
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
|
||||
index 0e85afa82c7..43756892e40 100644
|
||||
--- a/llvm/CMakeLists.txt
|
||||
+++ b/llvm/CMakeLists.txt
|
||||
@@ -505,8 +505,15 @@ option(LLVM_BUILD_RUNTIME
|
||||
"Build the LLVM runtime libraries." ON)
|
||||
option(LLVM_BUILD_EXAMPLES
|
||||
"Build the LLVM example programs. If OFF, just generate build targets." OFF)
|
||||
+option(BUILD_ARK_GC_SUPPORT
|
||||
+ "ARK support GC. If ON, support GC." OFF)
|
||||
+if(BUILD_ARK_GC_SUPPORT)
|
||||
+ add_definitions(-DARK_GC_SUPPORT)
|
||||
+endif(BUILD_ARK_GC_SUPPORT)
|
||||
+
|
||||
option(LLVM_INCLUDE_EXAMPLES "Generate build targets for the LLVM examples" ON)
|
||||
|
||||
+
|
||||
if(LLVM_BUILD_EXAMPLES)
|
||||
add_definitions(-DBUILD_EXAMPLES)
|
||||
endif(LLVM_BUILD_EXAMPLES)
|
||||
diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
|
||||
index c7d4c4d7e5d..1df40696dd0 100644
|
||||
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
|
||||
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
|
||||
@@ -15,6 +15,9 @@
|
||||
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+#include "llvm/ADT/Triple.h"
|
||||
+#endif
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -177,7 +180,12 @@ public:
|
||||
MachineBasicBlock &MBB) const = 0;
|
||||
virtual void emitEpilogue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const = 0;
|
||||
-
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ virtual Triple::ArchType GetArkSupportTarget() const
|
||||
+ {
|
||||
+ return Triple::UnknownArch;
|
||||
+ }
|
||||
+#endif
|
||||
/// Replace a StackProbe stub (if any) with the actual probe code inline
|
||||
virtual void inlineStackProbe(MachineFunction &MF,
|
||||
MachineBasicBlock &PrologueMBB) const {}
|
||||
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
|
||||
index 3909b571728..c8b3c1c2928 100644
|
||||
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
|
||||
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
|
||||
@@ -79,6 +79,8 @@ using MBBVector = SmallVector<MachineBasicBlock *, 4>;
|
||||
STATISTIC(NumLeafFuncWithSpills, "Number of leaf functions with CSRs");
|
||||
STATISTIC(NumFuncSeen, "Number of functions seen in PEI");
|
||||
|
||||
+#define JS_ENTRY_FRAME_MARK 1
|
||||
+#define JS_FRAME_MARK 0
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -878,6 +880,35 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &MF) {
|
||||
int64_t FixedCSEnd = Offset;
|
||||
unsigned MaxAlign = MFI.getMaxAlignment();
|
||||
|
||||
+ #ifdef ARK_GC_SUPPORT
|
||||
+ unsigned CalleeSavedFrameSize = 0;
|
||||
+ Triple::ArchType archType = TFI.GetArkSupportTarget();
|
||||
+ if (archType != Triple::UnknownArch) {
|
||||
+ int slotSize = 4;
|
||||
+ if (archType == Triple::aarch64) {
|
||||
+ slotSize = 8;
|
||||
+ }
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call")) {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ CalleeSavedFrameSize = 3 * slotSize;/* frameType + threadSP */
|
||||
+ } else if (marker == JS_FRAME_MARK){
|
||||
+ CalleeSavedFrameSize = 2 * slotSize; /* frameType */
|
||||
+ } else {
|
||||
+ assert("js-stub-call is illeagl ! ");
|
||||
+ }
|
||||
+ if (archType == Triple::aarch64) {
|
||||
+ CalleeSavedFrameSize += slotSize; /* current SP */
|
||||
+ }
|
||||
+ Offset += CalleeSavedFrameSize;
|
||||
+ }
|
||||
+ }
|
||||
+ #endif
|
||||
+
|
||||
// Make sure the special register scavenging spill slot is closest to the
|
||||
// incoming stack pointer if a frame pointer is required and is closer
|
||||
// to the incoming rather than the final stack pointer.
|
||||
diff --git a/llvm/lib/CodeGen/StackMaps.cpp b/llvm/lib/CodeGen/StackMaps.cpp
|
||||
index e16587c44a5..bd3e99c6600 100644
|
||||
--- a/llvm/lib/CodeGen/StackMaps.cpp
|
||||
+++ b/llvm/lib/CodeGen/StackMaps.cpp
|
||||
@@ -29,6 +29,9 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+#include "llvm/Target/TargetMachine.h"
|
||||
+#endif
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
@@ -442,7 +445,11 @@ void StackMaps::emitFunctionFrameRecords(MCStreamer &OS) {
|
||||
LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first
|
||||
<< " frame size: " << FR.second.StackSize
|
||||
<< " callsite count: " << FR.second.RecordCount << '\n');
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ OS.EmitSymbolValue(FR.first, AP.TM.getProgramPointerSize());
|
||||
+#else
|
||||
OS.EmitSymbolValue(FR.first, 8);
|
||||
+#endif
|
||||
OS.EmitIntValue(FR.second.StackSize, 8);
|
||||
OS.EmitIntValue(FR.second.RecordCount, 8);
|
||||
}
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
|
||||
index 6da089d1859..271b4e157d9 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
|
||||
@@ -95,6 +95,10 @@ public:
|
||||
const MachineInstr &MI);
|
||||
void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
const MachineInstr &MI);
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI);
|
||||
+#endif
|
||||
|
||||
void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI);
|
||||
void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI);
|
||||
@@ -936,6 +940,49 @@ void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
|
||||
}
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI) {
|
||||
+ StatepointOpers SOpers(&MI);
|
||||
+ if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
|
||||
+ assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
|
||||
+ for (unsigned i = 0; i < PatchBytes; i += 4)
|
||||
+ EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0));
|
||||
+ } else {
|
||||
+ // Lower call target and choose correct opcode
|
||||
+ const MachineOperand &CallTarget = SOpers.getCallTarget();
|
||||
+ MCOperand CallTargetMCOp;
|
||||
+ unsigned CallOpcode;
|
||||
+ switch (CallTarget.getType()) {
|
||||
+ case MachineOperand::MO_GlobalAddress:
|
||||
+ case MachineOperand::MO_ExternalSymbol:
|
||||
+ MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp);
|
||||
+ CallOpcode = AArch64::BL;
|
||||
+ break;
|
||||
+ case MachineOperand::MO_Immediate:
|
||||
+ CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
|
||||
+ CallOpcode = AArch64::BL;
|
||||
+ break;
|
||||
+ case MachineOperand::MO_Register:
|
||||
+ CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
|
||||
+ CallOpcode = AArch64::BLR;
|
||||
+ break;
|
||||
+ default:
|
||||
+ llvm_unreachable("Unsupported operand type in statepoint call target");
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ EmitToStreamer(OutStreamer,
|
||||
+ MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
|
||||
+ }
|
||||
+
|
||||
+ auto &Ctx = OutStreamer.getContext();
|
||||
+ MCSymbol *MILabel = Ctx.createTempSymbol();
|
||||
+ OutStreamer.EmitLabel(MILabel);
|
||||
+ SM.recordStatepoint(*MILabel, MI);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
void AArch64AsmPrinter::EmitFMov0(const MachineInstr &MI) {
|
||||
Register DestReg = MI.getOperand(0).getReg();
|
||||
if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround()) {
|
||||
@@ -1198,6 +1245,11 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
case TargetOpcode::PATCHPOINT:
|
||||
return LowerPATCHPOINT(*OutStreamer, SM, *MI);
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ case TargetOpcode::STATEPOINT:
|
||||
+ return LowerSTATEPOINT(*OutStreamer, SM, *MI);
|
||||
+#endif
|
||||
+
|
||||
case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
|
||||
LowerPATCHABLE_FUNCTION_ENTER(*MI);
|
||||
return;
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
|
||||
index 651ad9ad4c8..6e4a674be51 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
|
||||
@@ -872,6 +872,13 @@ static bool IsSVECalleeSave(MachineBasicBlock::iterator I) {
|
||||
}
|
||||
}
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+Triple::ArchType AArch64FrameLowering::GetArkSupportTarget() const
|
||||
+{
|
||||
+ return Triple::aarch64;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
MachineBasicBlock::iterator MBBI = MBB.begin();
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
|
||||
index b5719feb6b1..b09aa05176d 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
|
||||
@@ -15,6 +15,11 @@
|
||||
|
||||
#include "AArch64StackOffset.h"
|
||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+#include "llvm/ADT/Triple.h"
|
||||
+#endif
|
||||
+
|
||||
+#define JS_ENTRY_FRAME_MARK 1
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@@ -35,6 +40,9 @@ public:
|
||||
/// the function.
|
||||
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ Triple::ArchType GetArkSupportTarget() const override;
|
||||
+#endif
|
||||
|
||||
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;
|
||||
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
|
||||
index 23f05eaad94..9d42a9d9af9 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
|
||||
@@ -1498,6 +1498,9 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
|
||||
|
||||
case TargetOpcode::STACKMAP:
|
||||
case TargetOpcode::PATCHPOINT:
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ case TargetOpcode::STATEPOINT:
|
||||
+#endif
|
||||
return emitPatchPoint(MI, BB);
|
||||
|
||||
case AArch64::CATCHRET:
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
|
||||
index 54f3f7c1013..c57374c9c78 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
|
||||
@@ -107,6 +107,15 @@ unsigned AArch64InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
|
||||
NumBytes = PatchPointOpers(&MI).getNumPatchBytes();
|
||||
assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
|
||||
break;
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ case TargetOpcode::STATEPOINT:
|
||||
+ NumBytes = StatepointOpers(&MI).getNumPatchBytes();
|
||||
+ assert(NumBytes % 4 == 0 && "Invalid number of NOP bytes requested!");
|
||||
+ // No patch bytes means a normal call inst is emitted
|
||||
+ if (NumBytes == 0)
|
||||
+ NumBytes = 4;
|
||||
+ break;
|
||||
+#endif
|
||||
case AArch64::TLSDESC_CALLSEQ:
|
||||
// This gets lowered to an instruction sequence which takes 16 bytes
|
||||
NumBytes = 16;
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
|
||||
index 14f839cd4f8..f305d3abdbf 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
|
||||
@@ -464,8 +464,14 @@ void AArch64RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
unsigned FrameReg;
|
||||
|
||||
// Special handling of dbg_value, stackmap and patchpoint instructions.
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ if (MI.isDebugValue() || MI.getOpcode() == TargetOpcode::STACKMAP ||
|
||||
+ MI.getOpcode() == TargetOpcode::PATCHPOINT ||
|
||||
+ MI.getOpcode() == TargetOpcode::STATEPOINT) {
|
||||
+#else
|
||||
if (MI.isDebugValue() || MI.getOpcode() == TargetOpcode::STACKMAP ||
|
||||
MI.getOpcode() == TargetOpcode::PATCHPOINT) {
|
||||
+#endif
|
||||
StackOffset Offset =
|
||||
TFI->resolveFrameIndexReference(MF, FrameIndex, FrameReg,
|
||||
/*PreferFP=*/true,
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64StackOffset.h b/llvm/lib/Target/AArch64/AArch64StackOffset.h
|
||||
index f95b5dc5246..99f5905565a 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64StackOffset.h
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64StackOffset.h
|
||||
@@ -37,7 +37,7 @@ namespace llvm {
|
||||
class StackOffset {
|
||||
int64_t Bytes;
|
||||
int64_t ScalableBytes;
|
||||
-
|
||||
+public:
|
||||
explicit operator int() const;
|
||||
|
||||
public:
|
||||
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
|
||||
index 4724d6b8dae..2155ad923f9 100644
|
||||
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
|
||||
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
|
||||
@@ -189,6 +189,12 @@ int AArch64TTIImpl::getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
|
||||
if ((Idx < 4) || (Imm.getBitWidth() <= 64 && isInt<64>(Imm.getSExtValue())))
|
||||
return TTI::TCC_Free;
|
||||
break;
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ case Intrinsic::experimental_gc_statepoint:
|
||||
+ if ((Idx < 5) || (Imm.getBitWidth() <= 64 && isInt<64>(Imm.getSExtValue())))
|
||||
+ return TTI::TCC_Free;
|
||||
+ break;
|
||||
+#endif
|
||||
}
|
||||
return AArch64TTIImpl::getIntImmCost(Imm, Ty);
|
||||
}
|
||||
diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
|
||||
index 6f26ca127f9..8db2d2c4b0b 100644
|
||||
--- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
|
||||
+++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
|
||||
@@ -55,7 +55,11 @@ using namespace llvm;
|
||||
ARMAsmPrinter::ARMAsmPrinter(TargetMachine &TM,
|
||||
std::unique_ptr<MCStreamer> Streamer)
|
||||
: AsmPrinter(TM, std::move(Streamer)), Subtarget(nullptr), AFI(nullptr),
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ MCP(nullptr), InConstantPool(false), OptimizationGoals(-1), SM(*this) {}
|
||||
+#else
|
||||
MCP(nullptr), InConstantPool(false), OptimizationGoals(-1) {}
|
||||
+#endif
|
||||
|
||||
void ARMAsmPrinter::EmitFunctionBodyEnd() {
|
||||
// Make sure to terminate any constant pools that were at the end
|
||||
@@ -567,6 +571,10 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
||||
OptimizationGoals = -1;
|
||||
|
||||
ATS.finishAttributeSection();
|
||||
+
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ SM.serializeToStackMapSection();
|
||||
+#endif
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -2135,6 +2143,14 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
case ARM::PATCHABLE_TAIL_CALL:
|
||||
LowerPATCHABLE_TAIL_CALL(*MI);
|
||||
return;
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ case TargetOpcode::STACKMAP:
|
||||
+ return LowerSTACKMAP(*OutStreamer, SM, *MI);
|
||||
+ case TargetOpcode::PATCHPOINT:
|
||||
+ return LowerPATCHPOINT(*OutStreamer, SM, *MI);
|
||||
+ case TargetOpcode::STATEPOINT:
|
||||
+ return LowerSTATEPOINT(*OutStreamer, SM, *MI);
|
||||
+#endif
|
||||
}
|
||||
|
||||
MCInst TmpInst;
|
||||
@@ -2143,6 +2159,75 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
EmitToStreamer(*OutStreamer, TmpInst);
|
||||
}
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+static unsigned roundUpTo4ByteAligned(unsigned n) {
|
||||
+ unsigned mask = 3;
|
||||
+ unsigned rev = ~3;
|
||||
+ n = (n & rev) + (((n & mask) + mask) & rev);
|
||||
+ return n;
|
||||
+}
|
||||
+
|
||||
+void ARMAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI) {
|
||||
+ llvm_unreachable("Stackmap lowering is not implemented");
|
||||
+}
|
||||
+
|
||||
+void ARMAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI) {
|
||||
+ llvm_unreachable("Patchpoint lowering is not implemented");
|
||||
+}
|
||||
+
|
||||
+void ARMAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI) {
|
||||
+ assert(!AFI->isThumbFunction());
|
||||
+
|
||||
+ StatepointOpers SOpers(&MI);
|
||||
+ MCInst Noop;
|
||||
+ Subtarget->getInstrInfo()->getNoop(Noop);
|
||||
+ if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
|
||||
+ unsigned NumBytes = roundUpTo4ByteAligned(PatchBytes);
|
||||
+ unsigned EncodedBytes = 0;
|
||||
+ assert(NumBytes >= EncodedBytes &&
|
||||
+ "Statepoint can't request size less than the length of a call.");
|
||||
+ assert((NumBytes - EncodedBytes) % 4 == 0 &&
|
||||
+ "Invalid number of NOP bytes requested!");
|
||||
+ MCInst Noop;
|
||||
+ Subtarget->getInstrInfo()->getNoop(Noop);
|
||||
+ for (unsigned i = EncodedBytes; i < NumBytes; i += 4)
|
||||
+ EmitToStreamer(OutStreamer, Noop);
|
||||
+ } else {
|
||||
+ const MachineOperand &CallTarget = SOpers.getCallTarget();
|
||||
+ MCOperand CallTargetMCOp;
|
||||
+ unsigned CallOpcode;
|
||||
+ switch (CallTarget.getType()) {
|
||||
+ case MachineOperand::MO_GlobalAddress:
|
||||
+ case MachineOperand::MO_ExternalSymbol:
|
||||
+ ARMAsmPrinter::lowerOperand(CallTarget, CallTargetMCOp);
|
||||
+ CallOpcode = ARM::BL;
|
||||
+ break;
|
||||
+ case MachineOperand::MO_Immediate:
|
||||
+ CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
|
||||
+ CallOpcode = ARM::BL;
|
||||
+ break;
|
||||
+ case MachineOperand::MO_Register:
|
||||
+ CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
|
||||
+ CallOpcode = ARM::BLX;
|
||||
+ break;
|
||||
+ default:
|
||||
+ llvm_unreachable("Unsupported operand type in statepoint call target");
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ EmitToStreamer(OutStreamer,
|
||||
+ MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp));
|
||||
+ }
|
||||
+ auto &Ctx = OutStreamer.getContext();
|
||||
+ MCSymbol *MILabel = Ctx.createTempSymbol();
|
||||
+ OutStreamer.EmitLabel(MILabel);
|
||||
+ SM.recordStatepoint(*MILabel, MI);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Target Registry Stuff
|
||||
//===----------------------------------------------------------------------===//
|
||||
diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.h b/llvm/lib/Target/ARM/ARMAsmPrinter.h
|
||||
index a4b37fa2331..be62b1875f4 100644
|
||||
--- a/llvm/lib/Target/ARM/ARMAsmPrinter.h
|
||||
+++ b/llvm/lib/Target/ARM/ARMAsmPrinter.h
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
#include "ARMSubtarget.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+#include "llvm/CodeGen/StackMaps.h"
|
||||
+#endif
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
namespace llvm {
|
||||
@@ -65,6 +68,10 @@ class LLVM_LIBRARY_VISIBILITY ARMAsmPrinter : public AsmPrinter {
|
||||
/// debug info can link properly.
|
||||
SmallPtrSet<const GlobalVariable*,2> EmittedPromotedGlobalLabels;
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ StackMaps SM;
|
||||
+#endif
|
||||
+
|
||||
public:
|
||||
explicit ARMAsmPrinter(TargetMachine &TM,
|
||||
std::unique_ptr<MCStreamer> Streamer);
|
||||
@@ -129,6 +136,17 @@ private:
|
||||
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
|
||||
const MachineInstr *MI);
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI);
|
||||
+
|
||||
+ void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI);
|
||||
+
|
||||
+ void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
|
||||
+ const MachineInstr &MI);
|
||||
+#endif
|
||||
+
|
||||
public:
|
||||
unsigned getISAEncoding() override {
|
||||
// ARM/Darwin adds ISA to the DWARF info for each function.
|
||||
diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
|
||||
index 48f78151025..0970a6259ad 100644
|
||||
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
|
||||
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
|
||||
@@ -712,6 +712,11 @@ unsigned ARMBaseInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
|
||||
return 0;
|
||||
case TargetOpcode::BUNDLE:
|
||||
return getInstBundleLength(MI);
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ case TargetOpcode::PATCHPOINT:
|
||||
+ case TargetOpcode::STATEPOINT:
|
||||
+ return MI.getOperand(1).getImm();
|
||||
+#endif
|
||||
case ARM::MOVi16_ga_pcrel:
|
||||
case ARM::MOVTi16_ga_pcrel:
|
||||
case ARM::t2MOVi16_ga_pcrel:
|
||||
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
|
||||
index cb98b2b34ef..b39bdf6f48e 100644
|
||||
--- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp
|
||||
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
|
||||
@@ -353,6 +353,13 @@ static int getMaxFPOffset(const Function &F, const ARMFunctionInfo &AFI) {
|
||||
return -AFI.getArgRegsSaveSize() - (8 * 4);
|
||||
}
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+Triple::ArchType ARMFrameLowering::GetArkSupportTarget() const
|
||||
+{
|
||||
+ return Triple::arm;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
void ARMFrameLowering::emitPrologue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
MachineBasicBlock::iterator MBBI = MBB.begin();
|
||||
@@ -967,6 +974,33 @@ ARMFrameLowering::ResolveFrameIndexReference(const MachineFunction &MF,
|
||||
return Offset;
|
||||
}
|
||||
|
||||
+void ARMFrameLowering::emitPushJSInfo(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
+ unsigned StrOpc, unsigned MIFlags) const
|
||||
+{
|
||||
+ using RegAndKill = std::pair<unsigned, bool>;
|
||||
+ MachineFunction &MF = *MBB.getParent();
|
||||
+ const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
+ bool isLiveIn = true;
|
||||
+ DebugLoc DL;
|
||||
+ SmallVector<RegAndKill, 4> Regs;
|
||||
+ Regs.push_back(std::make_pair(ARM::R11, /*isKill=*/!isLiveIn));
|
||||
+ BuildMI(MBB, MI, DL, TII.get(StrOpc), ARM::SP)
|
||||
+ .addReg(Regs[0].first, getKillRegState(Regs[0].second))
|
||||
+ .addReg(ARM::SP)
|
||||
+ .setMIFlags(MIFlags)
|
||||
+ .addImm(-4)
|
||||
+ .add(predOps(ARMCC::AL));
|
||||
+}
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
|
||||
+ MachineBasicBlock::iterator MI,
|
||||
+ const std::vector<CalleeSavedInfo> &CSI,
|
||||
+ unsigned StmOpc, unsigned StrOpc,
|
||||
+ bool NoGap,
|
||||
+ bool(*Func)(unsigned, bool),
|
||||
+ unsigned NumAlignedDPRCS2Regs,
|
||||
+ unsigned MIFlags, int multiCall) const {
|
||||
+#else
|
||||
void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
const std::vector<CalleeSavedInfo> &CSI,
|
||||
@@ -975,6 +1009,7 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
|
||||
bool(*Func)(unsigned, bool),
|
||||
unsigned NumAlignedDPRCS2Regs,
|
||||
unsigned MIFlags) const {
|
||||
+#endif
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
|
||||
@@ -1019,7 +1054,26 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
|
||||
llvm::sort(Regs, [&](const RegAndKill &LHS, const RegAndKill &RHS) {
|
||||
return TRI.getEncodingValue(LHS.first) < TRI.getEncodingValue(RHS.first);
|
||||
});
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ SmallVector<RegAndKill, 4> BeforeRegs = Regs;
|
||||
+ if (multiCall != 0) {
|
||||
+ Regs.clear();
|
||||
+ }
|
||||
+ if (multiCall == 1) {
|
||||
+ for (auto it: BeforeRegs) {
|
||||
+ if (it.first == ARM::LR || it.first == ARM::R11) {
|
||||
+ Regs.push_back(it);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
+ } else if (multiCall == 2) {
|
||||
+ for (auto it: BeforeRegs) {
|
||||
+ if ((it.first != ARM::LR) && (it.first != ARM::R11)) {
|
||||
+ Regs.push_back(it);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
if (Regs.size() > 1 || StrOpc== 0) {
|
||||
MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StmOpc), ARM::SP)
|
||||
.addReg(ARM::SP)
|
||||
@@ -1045,6 +1099,38 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
|
||||
}
|
||||
}
|
||||
|
||||
+void ARMFrameLowering::emitPopJSInfo(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
+ unsigned LdrOpc) const
|
||||
+{
|
||||
+ MachineFunction &MF = *MBB.getParent();
|
||||
+ const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
+ SmallVector<unsigned, 4> Regs;
|
||||
+ unsigned Reg = ARM::R11;
|
||||
+ Regs.push_back(Reg);
|
||||
+ DebugLoc DL;
|
||||
+ MachineInstrBuilder MIB =
|
||||
+ BuildMI(MBB, MI, DL, TII.get(LdrOpc), Regs[0])
|
||||
+ .addReg(ARM::SP, RegState::Define)
|
||||
+ .addReg(ARM::SP);
|
||||
+ // ARM mode needs an extra reg0 here due to addrmode2. Will go away once
|
||||
+ // that refactoring is complete (eventually).
|
||||
+ if (LdrOpc == ARM::LDR_POST_REG || LdrOpc == ARM::LDR_POST_IMM) {
|
||||
+ MIB.addReg(0);
|
||||
+ MIB.addImm(ARM_AM::getAM2Opc(ARM_AM::add, 4, ARM_AM::no_shift));
|
||||
+ } else
|
||||
+ MIB.addImm(4);
|
||||
+ MIB.add(predOps(ARMCC::AL));
|
||||
+}
|
||||
+
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
|
||||
+ MachineBasicBlock::iterator MI,
|
||||
+ std::vector<CalleeSavedInfo> &CSI,
|
||||
+ unsigned LdmOpc, unsigned LdrOpc,
|
||||
+ bool isVarArg, bool NoGap,
|
||||
+ bool(*Func)(unsigned, bool),
|
||||
+ unsigned NumAlignedDPRCS2Regs, int multiCall) const {
|
||||
+#else
|
||||
void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
std::vector<CalleeSavedInfo> &CSI,
|
||||
@@ -1052,6 +1138,7 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
|
||||
bool isVarArg, bool NoGap,
|
||||
bool(*Func)(unsigned, bool),
|
||||
unsigned NumAlignedDPRCS2Regs) const {
|
||||
+#endif
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
||||
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
|
||||
@@ -1116,6 +1203,26 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
|
||||
return TRI.getEncodingValue(LHS) < TRI.getEncodingValue(RHS);
|
||||
});
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ SmallVector<unsigned, 4> BeforeRegs = Regs;
|
||||
+ if (multiCall != 0) {
|
||||
+ Regs.clear();
|
||||
+ }
|
||||
+ if (multiCall == 1) {
|
||||
+ for (auto it: BeforeRegs) {
|
||||
+ if ((it != ARM::LR) && (it != ARM::R11)) {
|
||||
+ Regs.push_back(it);
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (multiCall == 2) {
|
||||
+ for (auto it: BeforeRegs) {
|
||||
+ if ((it == ARM::LR) || (it == ARM::R11)) {
|
||||
+ Regs.push_back(it);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (Regs.size() > 1 || LdrOpc == 0) {
|
||||
MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(LdmOpc), ARM::SP)
|
||||
.addReg(ARM::SP)
|
||||
@@ -1422,6 +1529,27 @@ static void emitAlignedDPRCS2Restores(MachineBasicBlock &MBB,
|
||||
std::prev(MI)->addRegisterKilled(ARM::R4, TRI);
|
||||
}
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+int ARMFrameLowering::GetSlotForJSInfo(const MachineFunction &MF) const {
|
||||
+ int reserverSlot = 0;
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call")) {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ reserverSlot = 3; // 3 * slotSize;/* frameType + threadSP */
|
||||
+ } else if (marker == JS_FRAME_MARK){
|
||||
+ reserverSlot = 2; /* frameType */
|
||||
+ } else {
|
||||
+ assert("js-stub-call is illeagl ! ");
|
||||
+ }
|
||||
+ }
|
||||
+ return reserverSlot;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
bool ARMFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
const std::vector<CalleeSavedInfo> &CSI,
|
||||
@@ -1436,9 +1564,23 @@ bool ARMFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
unsigned PushOneOpc = AFI->isThumbFunction() ?
|
||||
ARM::t2STR_PRE : ARM::STR_PRE_IMM;
|
||||
unsigned FltOpc = ARM::VSTMDDB_UPD;
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ DebugLoc DL;
|
||||
+ const ARMBaseInstrInfo &TII =
|
||||
+ *static_cast<const ARMBaseInstrInfo *>(MF.getSubtarget().getInstrInfo());
|
||||
unsigned NumAlignedDPRCS2Regs = AFI->getNumAlignedDPRCS2Regs();
|
||||
+ emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register, 0,
|
||||
+ MachineInstr::FrameSetup, 1);
|
||||
+ for (int i = 0; i < GetSlotForJSInfo(MF); i++) {
|
||||
+ emitPushJSInfo(MBB, MI, PushOneOpc, MachineInstr::FrameSetup);
|
||||
+ }
|
||||
+
|
||||
+ emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register, 0,
|
||||
+ MachineInstr::FrameSetup, 2);
|
||||
+#else
|
||||
emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register, 0,
|
||||
MachineInstr::FrameSetup);
|
||||
+#endif
|
||||
emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea2Register, 0,
|
||||
MachineInstr::FrameSetup);
|
||||
emitPushInst(MBB, MI, CSI, FltOpc, 0, true, &isARMArea3Register,
|
||||
@@ -1477,8 +1619,20 @@ bool ARMFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
NumAlignedDPRCS2Regs);
|
||||
emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
|
||||
&isARMArea2Register, 0);
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
|
||||
+ &isARMArea1Register, 0, 1);
|
||||
+
|
||||
+ for (int i = 0; i < GetSlotForJSInfo(MF); i++) {
|
||||
+ emitPopJSInfo(MBB, MI, LdrOpc);
|
||||
+ }
|
||||
+
|
||||
+ emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
|
||||
+ &isARMArea1Register, 0, 2);
|
||||
+#else
|
||||
emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
|
||||
&isARMArea1Register, 0);
|
||||
+#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1573,7 +1727,7 @@ static unsigned estimateRSStackSizeLimit(MachineFunction &MF,
|
||||
Limit = std::min(Limit, ((1U << 7) - 1) * 4);
|
||||
break;
|
||||
default:
|
||||
- llvm_unreachable("Unhandled addressing mode in stack size limit calculation");
|
||||
+ break;
|
||||
}
|
||||
break; // At most one FI per instruction
|
||||
}
|
||||
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.h b/llvm/lib/Target/ARM/ARMFrameLowering.h
|
||||
index 0462b01af70..c410326f432 100644
|
||||
--- a/llvm/lib/Target/ARM/ARMFrameLowering.h
|
||||
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.h
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||
#include <vector>
|
||||
|
||||
+#define JS_ENTRY_FRAME_MARK 1
|
||||
+#define JS_FRAME_MARK 0
|
||||
+
|
||||
namespace llvm {
|
||||
|
||||
class ARMSubtarget;
|
||||
@@ -30,6 +33,9 @@ public:
|
||||
/// the function.
|
||||
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ Triple::ArchType GetArkSupportTarget() const override;
|
||||
+#endif
|
||||
|
||||
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
@@ -72,6 +78,24 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
+
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ void emitPushInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
+ const std::vector<CalleeSavedInfo> &CSI, unsigned StmOpc,
|
||||
+ unsigned StrOpc, bool NoGap,
|
||||
+ bool(*Func)(unsigned, bool), unsigned NumAlignedDPRCS2Regs,
|
||||
+ unsigned MIFlags = 0, int multiCall = 0) const;
|
||||
+ void emitPushJSInfo(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
+ unsigned StrOpc, unsigned MIFlags) const;
|
||||
+ void emitPopInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
+ std::vector<CalleeSavedInfo> &CSI, unsigned LdmOpc,
|
||||
+ unsigned LdrOpc, bool isVarArg, bool NoGap,
|
||||
+ bool(*Func)(unsigned, bool),
|
||||
+ unsigned NumAlignedDPRCS2Regs, int multiCall = 0) const;
|
||||
+ void emitPopJSInfo(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
+ unsigned LdrOpc) const;
|
||||
+ int GetSlotForJSInfo(const MachineFunction &MF) const;
|
||||
+#else
|
||||
void emitPushInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
const std::vector<CalleeSavedInfo> &CSI, unsigned StmOpc,
|
||||
unsigned StrOpc, bool NoGap,
|
||||
@@ -82,7 +106,7 @@ private:
|
||||
unsigned LdrOpc, bool isVarArg, bool NoGap,
|
||||
bool(*Func)(unsigned, bool),
|
||||
unsigned NumAlignedDPRCS2Regs) const;
|
||||
-
|
||||
+#endif
|
||||
MachineBasicBlock::iterator
|
||||
eliminateCallFramePseudoInstr(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB,
|
||||
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
|
||||
index 9f504b1eaa4..cf2f5f50b14 100644
|
||||
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
|
||||
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
|
||||
@@ -10551,6 +10551,13 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
llvm_unreachable("Unexpected instr type to insert");
|
||||
}
|
||||
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ case TargetOpcode::STATEPOINT:
|
||||
+ case TargetOpcode::STACKMAP:
|
||||
+ case TargetOpcode::PATCHPOINT:
|
||||
+ return emitPatchPoint(MI, BB);
|
||||
+#endif
|
||||
+
|
||||
// Thumb1 post-indexed loads are really just single-register LDMs.
|
||||
case ARM::tLDR_postidx: {
|
||||
MachineOperand Def(MI.getOperand(1));
|
||||
diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
|
||||
index 1da20371caf..a73d3cd8053 100644
|
||||
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
|
||||
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
|
||||
@@ -1168,6 +1168,25 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
|
||||
else
|
||||
MFI.setOffsetAdjustment(-StackSize);
|
||||
}
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ // push marker
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call"))
|
||||
+ {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64i32 : X86::PUSH32i8))
|
||||
+ .addImm(marker)
|
||||
+ .setMIFlag(MachineInstr::FrameSetup);
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64i32 : X86::PUSH32i8))
|
||||
+ .addImm(marker)
|
||||
+ .setMIFlag(MachineInstr::FrameSetup);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
// For EH funclets, only allocate enough space for outgoing calls. Save the
|
||||
// NumBytes value that we would've used for the parent frame.
|
||||
@@ -1635,6 +1654,27 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
uint64_t SEHStackAllocAmt = NumBytes;
|
||||
|
||||
if (HasFP) {
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call"))
|
||||
+ {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+
|
||||
+ // pop marker
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
|
||||
+ MachineFramePtr)
|
||||
+ .setMIFlag(MachineInstr::FrameDestroy);
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ // pop thread.fp
|
||||
+ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
|
||||
+ MachineFramePtr)
|
||||
+ .setMIFlag(MachineInstr::FrameDestroy);
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
// Pop EBP.
|
||||
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
|
||||
MachineFramePtr)
|
||||
@@ -1993,8 +2033,33 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots(
|
||||
|
||||
if (hasFP(MF)) {
|
||||
// emitPrologue always spills frame register the first thing.
|
||||
+#ifdef ARK_GC_SUPPORT
|
||||
+ if (MF.getFunction().hasFnAttribute("js-stub-call")) {
|
||||
+ int64_t marker = 0x0;
|
||||
+ MF.getFunction()
|
||||
+ .getFnAttribute("js-stub-call")
|
||||
+ .getValueAsString()
|
||||
+ .getAsInteger(10, marker);//marker 1 break frame
|
||||
+ if (marker == JS_ENTRY_FRAME_MARK) {
|
||||
+ SpillSlotOffset -= 3 * SlotSize; // add type and thread.fp
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ CalleeSavedFrameSize += (2 * SlotSize);
|
||||
+ } else {
|
||||
+ SpillSlotOffset -= 2 * SlotSize; // add type
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ CalleeSavedFrameSize += SlotSize;
|
||||
+ }
|
||||
+ } else {
|
||||
+ SpillSlotOffset -= SlotSize; // add type and thread.fp
|
||||
+ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+ }
|
||||
+#else
|
||||
SpillSlotOffset -= SlotSize;
|
||||
MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset);
|
||||
+#endif
|
||||
|
||||
// Since emitPrologue and emitEpilogue will handle spilling and restoring of
|
||||
// the frame register, we can delete it from CSI list and not have to worry
|
||||
diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h
|
||||
index 2103d6471ea..3fd89b0d9ee 100644
|
||||
--- a/llvm/lib/Target/X86/X86FrameLowering.h
|
||||
+++ b/llvm/lib/Target/X86/X86FrameLowering.h
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||
|
||||
+#define JS_ENTRY_FRAME_MARK 1
|
||||
+
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstrBuilder;
|
||||
@@ -14,9 +14,14 @@
|
||||
*/
|
||||
|
||||
#include "llvm_stackmap_parser.h"
|
||||
#include <iostream>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "ecmascript/compiler/compiler_macros.h"
|
||||
#include "ecmascript/frames.h"
|
||||
#include "ecmascript/mem/heap_roots.h"
|
||||
#include "ecmascript/mem/slots.h"
|
||||
|
||||
namespace kungfu {
|
||||
std::string LocationTy::TypeToString(Kind loc) const
|
||||
@@ -37,51 +42,80 @@ std::string LocationTy::TypeToString(Kind loc) const
|
||||
}
|
||||
}
|
||||
|
||||
bool LLVMStackMapParser::StackMapByAddr(uintptr_t funcAddr, DwarfRegAndOffsetTypeVector &infos)
|
||||
const DwarfRegAndOffsetTypeVector* LLVMStackMapParser::StackMapByAddr(uintptr_t callSiteAddr) const
|
||||
{
|
||||
bool found = false;
|
||||
for (auto it: callSiteInfos_) {
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << __FUNCTION__ << std::hex << " addr:" << it.first << std::endl;
|
||||
#endif
|
||||
if (it.first == funcAddr) {
|
||||
DwarfRegAndOffsetType info = it.second;
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << __FUNCTION__ << " info <" << info.first << " ," << info.second << " >" << std::endl;
|
||||
#endif
|
||||
infos.push_back(info);
|
||||
found = true;
|
||||
}
|
||||
auto it = callSiteInfos_.find(callSiteAddr);
|
||||
if (it != callSiteInfos_.end()) {
|
||||
return &(it->second);
|
||||
}
|
||||
return found;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool LLVMStackMapParser::StackMapByFuncAddrFp(uintptr_t funcAddr, uintptr_t frameFp,
|
||||
std::set<uintptr_t> &slotAddrs)
|
||||
bool LLVMStackMapParser::StackMapByFuncAddrFp(uintptr_t callSiteAddr, uintptr_t frameFp,
|
||||
const RootVisitor &v0, const RootRangeVisitor &v1,
|
||||
panda::ecmascript::ChunkVector<DerivedData> *data,
|
||||
[[maybe_unused]] bool isVerifying) const
|
||||
{
|
||||
DwarfRegAndOffsetTypeVector infos;
|
||||
if (!StackMapByAddr(funcAddr, infos)) {
|
||||
const DwarfRegAndOffsetTypeVector *infos = StackMapByAddr(callSiteAddr);
|
||||
if (infos == nullptr) {
|
||||
return false;
|
||||
}
|
||||
uintptr_t *fp = reinterpret_cast<uintptr_t *>(frameFp);
|
||||
uintptr_t **address = nullptr;
|
||||
for (auto &info: infos) {
|
||||
if (info.first == SP_DWARF_REG_NUM) {
|
||||
uintptr_t *rsp = fp + SP_OFFSET;
|
||||
address = reinterpret_cast<uintptr_t **>(reinterpret_cast<uintptr_t>(rsp) + info.second);
|
||||
} else if (info.first == FP_DWARF_REG_NUM) {
|
||||
fp = reinterpret_cast<uintptr_t *>(*fp);
|
||||
address = reinterpret_cast<uintptr_t **>(reinterpret_cast<uint8_t *>(fp) + info.second);
|
||||
uintptr_t address = 0;
|
||||
uintptr_t base = 0;
|
||||
uintptr_t derived = 0;
|
||||
int i = 0;
|
||||
for (auto &info: *infos) {
|
||||
if (info.first == panda::ecmascript::FrameConst::SP_DWARF_REG_NUM) {
|
||||
#ifdef PANDA_TARGET_ARM64
|
||||
uintptr_t *curFp = reinterpret_cast<uintptr_t *>(*fp);
|
||||
uintptr_t *rsp = reinterpret_cast<uintptr_t *>(*(curFp + panda::ecmascript::FrameConst::SP_OFFSET));
|
||||
#else
|
||||
uintptr_t *rsp = fp + panda::ecmascript::FrameConst::SP_OFFSET;
|
||||
#endif
|
||||
address = reinterpret_cast<uintptr_t>(rsp) + info.second;
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << "SP_DWARF_REG_NUM: info.second:" << info.second << " rbp offset:" <<
|
||||
reinterpret_cast<uintptr_t>(*fp) - address << "rsp :" << rsp;
|
||||
#endif
|
||||
} else if (info.first == panda::ecmascript::FrameConst::FP_DWARF_REG_NUM) {
|
||||
uintptr_t tmpFp = *fp;
|
||||
address = tmpFp + info.second;
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << "FP_DWARF_REG_NUM: info.second:" << info.second;
|
||||
#endif
|
||||
} else {
|
||||
address = nullptr;
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << "REG_NUM : info.first:" << info.first;
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << std::hex << "stackMap ref addr:" << address;
|
||||
LOG_ECMA(INFO) << " value:" << *address;
|
||||
LOG_ECMA(INFO) << " *value :" << **address << std::endl;
|
||||
|
||||
if (i & 0x1) {
|
||||
derived = reinterpret_cast<uintptr_t>(address);
|
||||
if (base == derived) {
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << std::hex << "visit base:" << base << " base Value: " <<
|
||||
*reinterpret_cast<uintptr_t *>(base);
|
||||
#endif
|
||||
slotAddrs.insert(reinterpret_cast<uintptr_t>(address));
|
||||
v0(panda::ecmascript::Root::ROOT_FRAME, panda::ecmascript::ObjectSlot(base));
|
||||
} else {
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << std::hex << "push base:" << base << " base Value: " <<
|
||||
*reinterpret_cast<uintptr_t *>(base) << " derived:" << derived;
|
||||
#endif
|
||||
#if ECMASCRIPT_ENABLE_HEAP_VERIFY
|
||||
if (!isVerifying) {
|
||||
#endif
|
||||
data->emplace_back(std::make_tuple(base, *reinterpret_cast<uintptr_t *>(base), derived));
|
||||
#if ECMASCRIPT_ENABLE_HEAP_VERIFY
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
base = reinterpret_cast<uintptr_t>(address);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -96,9 +130,18 @@ void LLVMStackMapParser::CalcCallSite()
|
||||
uint32_t instructionOffset = recordHead.InstructionOffset;
|
||||
uintptr_t callsite = address + instructionOffset;
|
||||
if (loc.location == LocationTy::Kind::INDIRECT) {
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << "DwarfRegNum:" << loc.DwarfRegNum << " loc.OffsetOrSmallConstant:" <<
|
||||
loc.OffsetOrSmallConstant << "address:" << address << " instructionOffset:" <<
|
||||
instructionOffset << " callsite:" << callsite;
|
||||
#endif
|
||||
DwarfRegAndOffsetType info(loc.DwarfRegNum, loc.OffsetOrSmallConstant);
|
||||
Fun2InfoType callSiteInfo {callsite, info};
|
||||
callSiteInfos_.push_back(callSiteInfo);
|
||||
auto it = callSiteInfos_.find(callsite);
|
||||
if (callSiteInfos_.find(callsite) == callSiteInfos_.end()) {
|
||||
callSiteInfos_.insert(std::pair<uintptr_t, DwarfRegAndOffsetTypeVector>(callsite, {info}));
|
||||
} else {
|
||||
it->second.emplace_back(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -112,14 +155,14 @@ void LLVMStackMapParser::CalcCallSite()
|
||||
}
|
||||
}
|
||||
|
||||
bool LLVMStackMapParser::CalculateStackMap(const uint8_t *stackMapAddr)
|
||||
bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr)
|
||||
{
|
||||
stackMapAddr_ = stackMapAddr;
|
||||
stackMapAddr_ = std::move(stackMapAddr);
|
||||
if (!stackMapAddr_) {
|
||||
LOG_ECMA(ERROR) << "stackMapAddr_ nullptr error ! " << std::endl;
|
||||
return false;
|
||||
}
|
||||
dataInfo_ = std::make_unique<DataInfo>(stackMapAddr_);
|
||||
dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr_));
|
||||
llvmStackMap_.head = dataInfo_->Read<struct Header>();
|
||||
uint32_t numFunctions, numConstants, numRecords;
|
||||
numFunctions = dataInfo_->Read<uint32_t>();
|
||||
@@ -161,24 +204,23 @@ bool LLVMStackMapParser::CalculateStackMap(const uint8_t *stackMapAddr)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLVMStackMapParser::CalculateStackMap(const uint8_t *stackMapAddr,
|
||||
bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr,
|
||||
uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr)
|
||||
{
|
||||
bool ret = CalculateStackMap(stackMapAddr);
|
||||
bool ret = CalculateStackMap(std::move(stackMapAddr));
|
||||
if (!ret) {
|
||||
return ret;
|
||||
}
|
||||
// update functionAddress from host side to device side
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << "stackmap calculate update funcitonaddress " << std::endl;
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << "stackmap calculate update funcitonaddress ";
|
||||
#endif
|
||||
for (size_t i = 0; i < llvmStackMap_.StkSizeRecords.size(); i++) {
|
||||
uintptr_t hostAddr = llvmStackMap_.StkSizeRecords[i].functionAddress;
|
||||
uintptr_t deviceAddr = hostAddr - hostCodeSectionAddr + deviceCodeSectionAddr;
|
||||
llvmStackMap_.StkSizeRecords[i].functionAddress = deviceAddr;
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << std::dec << i << "th function " << std::hex << hostAddr << " ---> " << deviceAddr
|
||||
<< std::endl;
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LOG_ECMA(DEBUG) << std::dec << i << "th function " << std::hex << hostAddr << " ---> " << deviceAddr;
|
||||
#endif
|
||||
}
|
||||
callSiteInfos_.clear();
|
||||
|
||||
@@ -1,230 +1,230 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H
|
||||
#define ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "ecmascript/common.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
|
||||
#ifdef PANDA_TARGET_AMD64
|
||||
#define SP_DWARF_REG_NUM 7
|
||||
#define FP_DWARF_REG_NUM 6
|
||||
#define SP_OFFSET 2
|
||||
#else
|
||||
#define SP_DWARF_REG_NUM 0
|
||||
#define FP_DWARF_REG_NUM 0
|
||||
#define SP_OFFSET 0
|
||||
#endif
|
||||
|
||||
namespace kungfu {
|
||||
using OffsetType = int32_t;
|
||||
using DwarfRegType = uint16_t;
|
||||
using DwarfRegAndOffsetType = std::pair<DwarfRegType, OffsetType>;
|
||||
using DwarfRegAndOffsetTypeVector = std::vector<DwarfRegAndOffsetType>;
|
||||
using Fun2InfoType = std::pair<uintptr_t, DwarfRegAndOffsetType>;
|
||||
|
||||
struct Header {
|
||||
uint8_t stackmapversion; // Stack Map Version (current version is 3)
|
||||
uint8_t Reserved0; // Reserved (expected to be 0)
|
||||
uint16_t Reserved1; // Reserved (expected to be 0)
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(INFO) << "----- head ----" << std::endl;
|
||||
LOG_ECMA(INFO) << " version:" << static_cast<int>(stackmapversion) << std::endl;
|
||||
LOG_ECMA(INFO) << "+++++ head ++++" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct StkSizeRecordTy {
|
||||
uint64_t functionAddress;
|
||||
uint64_t stackSize;
|
||||
uint64_t recordCount;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(INFO) << " functionAddress:0x" << std::hex << functionAddress << std::endl;
|
||||
LOG_ECMA(INFO) << " stackSize:" << std::dec << stackSize << std::endl;
|
||||
LOG_ECMA(INFO) << " recordCount:" << std::dec << recordCount << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct ConstantsTy {
|
||||
uint64_t LargeConstant;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(INFO) << " LargeConstant:" << LargeConstant << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct StkMapRecordHeadTy {
|
||||
uint64_t PatchPointID;
|
||||
uint32_t InstructionOffset;
|
||||
uint16_t Reserved;
|
||||
uint16_t NumLocations;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(INFO) << " PatchPointID:" << std::hex << PatchPointID << std::endl;
|
||||
LOG_ECMA(INFO) << " instructionOffset:" << std::hex << InstructionOffset << std::endl;
|
||||
LOG_ECMA(INFO) << " Reserved:" << Reserved << std::endl;
|
||||
LOG_ECMA(INFO) << " NumLocations:" << NumLocations << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct LocationTy {
|
||||
enum class Kind: uint8_t {
|
||||
REGISTER = 1,
|
||||
DIRECT = 2,
|
||||
INDIRECT = 3,
|
||||
CONSTANT = 4,
|
||||
CONSTANTNDEX = 5,
|
||||
};
|
||||
Kind location;
|
||||
uint8_t Reserved_0;
|
||||
uint16_t LocationSize;
|
||||
uint16_t DwarfRegNum;
|
||||
uint16_t Reserved_1;
|
||||
OffsetType OffsetOrSmallConstant;
|
||||
|
||||
std::string PUBLIC_API TypeToString(Kind loc) const;
|
||||
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(INFO) << TypeToString(location);
|
||||
LOG_ECMA(INFO) << ", size:" << std::dec << LocationSize;
|
||||
LOG_ECMA(INFO) << "\tDwarfRegNum:" << DwarfRegNum;
|
||||
LOG_ECMA(INFO) << "\t OffsetOrSmallConstant:" << OffsetOrSmallConstant << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct LiveOutsTy {
|
||||
DwarfRegType DwarfRegNum;
|
||||
uint8_t Reserved;
|
||||
uint8_t SizeinBytes;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(INFO) << " Dwarf RegNum:" << DwarfRegNum << std::endl;
|
||||
LOG_ECMA(INFO) << " Reserved:" << Reserved << std::endl;
|
||||
LOG_ECMA(INFO) << " SizeinBytes:" << SizeinBytes << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct StkMapRecordTy {
|
||||
struct StkMapRecordHeadTy head;
|
||||
std::vector<struct LocationTy> Locations;
|
||||
std::vector<struct LiveOutsTy> LiveOuts;
|
||||
void Print() const
|
||||
{
|
||||
head.Print();
|
||||
auto size = Locations.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
LOG_ECMA(INFO) << " #" << std::dec << i << ":";
|
||||
Locations[i].Print();
|
||||
}
|
||||
size = LiveOuts.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
LOG_ECMA(INFO) << " liveOuts[" << i << "] info:" << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DataInfo {
|
||||
public:
|
||||
explicit DataInfo(const uint8_t *data): data_(data), offset_(0) {}
|
||||
~DataInfo()
|
||||
{
|
||||
data_ = nullptr;
|
||||
offset_ = 0;
|
||||
}
|
||||
template<class T>
|
||||
T Read()
|
||||
{
|
||||
T t = *reinterpret_cast<const T*>(data_ + offset_);
|
||||
offset_ += sizeof(T);
|
||||
return t;
|
||||
}
|
||||
unsigned int GetOffset() const
|
||||
{
|
||||
return offset_;
|
||||
}
|
||||
private:
|
||||
const uint8_t *data_;
|
||||
unsigned int offset_;
|
||||
};
|
||||
|
||||
struct LLVMStackMap {
|
||||
struct Header head;
|
||||
std::vector<struct StkSizeRecordTy> StkSizeRecords;
|
||||
std::vector<struct ConstantsTy> Constants;
|
||||
std::vector<struct StkMapRecordTy> StkMapRecord;
|
||||
void Print() const
|
||||
{
|
||||
head.Print();
|
||||
for (size_t i = 0; i < StkSizeRecords.size(); i++) {
|
||||
LOG_ECMA(INFO) << "stkSizeRecord[" << i << "] info:" << std::endl;
|
||||
StkSizeRecords[i].Print();
|
||||
}
|
||||
for (size_t i = 0; i < Constants.size(); i++) {
|
||||
LOG_ECMA(INFO) << "constants[" << i << "] info:" << std::endl;
|
||||
Constants[i].Print();
|
||||
}
|
||||
for (size_t i = 0; i < StkMapRecord.size(); i++) {
|
||||
LOG_ECMA(INFO) << "StkMapRecord[" << i << "] info:" << std::endl;
|
||||
StkMapRecord[i].Print();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class LLVMStackMapParser {
|
||||
public:
|
||||
static LLVMStackMapParser& GetInstance()
|
||||
{
|
||||
static LLVMStackMapParser instance;
|
||||
return instance;
|
||||
}
|
||||
bool PUBLIC_API CalculateStackMap(const uint8_t *stackMapAddr);
|
||||
bool PUBLIC_API CalculateStackMap(const uint8_t *stackMapAddr,
|
||||
uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr);
|
||||
void PUBLIC_API Print() const
|
||||
{
|
||||
llvmStackMap_.Print();
|
||||
}
|
||||
bool StackMapByAddr(uintptr_t funcAddr, DwarfRegAndOffsetTypeVector &infos);
|
||||
bool StackMapByFuncAddrFp(uintptr_t funcAddr, uintptr_t frameFp,
|
||||
std::set<uintptr_t> &slotAddrs);
|
||||
private:
|
||||
LLVMStackMapParser()
|
||||
{
|
||||
stackMapAddr_ = nullptr;
|
||||
callSiteInfos_.clear();
|
||||
dataInfo_ = nullptr;
|
||||
}
|
||||
~LLVMStackMapParser()
|
||||
{
|
||||
stackMapAddr_ = nullptr;
|
||||
callSiteInfos_.clear();
|
||||
dataInfo_ = nullptr;
|
||||
}
|
||||
void CalcCallSite();
|
||||
const uint8_t *stackMapAddr_;
|
||||
struct LLVMStackMap llvmStackMap_;
|
||||
std::vector<Fun2InfoType> callSiteInfos_;
|
||||
[[maybe_unused]] std::unique_ptr<DataInfo> dataInfo_;
|
||||
};
|
||||
} // namespace kungfu
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H
|
||||
#define ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "ecmascript/common.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
|
||||
|
||||
namespace kungfu {
|
||||
using OffsetType = int32_t;
|
||||
using DwarfRegType = uint16_t;
|
||||
using DwarfRegAndOffsetType = std::pair<DwarfRegType, OffsetType>;
|
||||
using DwarfRegAndOffsetTypeVector = std::vector<DwarfRegAndOffsetType>;
|
||||
using Fun2InfoType = std::pair<uintptr_t, DwarfRegAndOffsetType>;
|
||||
using DerivedData = panda::ecmascript::DerivedData;
|
||||
using RootVisitor = panda::ecmascript::RootVisitor;
|
||||
using RootRangeVisitor = panda::ecmascript::RootRangeVisitor;
|
||||
|
||||
struct Header {
|
||||
uint8_t stackmapversion; // Stack Map Version (current version is 3)
|
||||
uint8_t Reserved0; // Reserved (expected to be 0)
|
||||
uint16_t Reserved1; // Reserved (expected to be 0)
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(DEBUG) << "----- head ----";
|
||||
LOG_ECMA(DEBUG) << " version:" << static_cast<int>(stackmapversion);
|
||||
LOG_ECMA(DEBUG) << "+++++ head ++++";
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct StkSizeRecordTy {
|
||||
uintptr_t functionAddress;
|
||||
uint64_t stackSize;
|
||||
uint64_t recordCount;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(DEBUG) << " functionAddress:0x" << std::hex << functionAddress;
|
||||
LOG_ECMA(DEBUG) << " stackSize:0x" << std::hex << stackSize;
|
||||
LOG_ECMA(DEBUG) << " recordCount:" << std::hex << recordCount;
|
||||
}
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
struct ConstantsTy {
|
||||
uintptr_t LargeConstant;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(DEBUG) << " LargeConstant:0x" << std::hex << LargeConstant;
|
||||
}
|
||||
};
|
||||
|
||||
struct StkMapRecordHeadTy {
|
||||
uint64_t PatchPointID;
|
||||
uint32_t InstructionOffset;
|
||||
uint16_t Reserved;
|
||||
uint16_t NumLocations;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(DEBUG) << " PatchPointID:0x" << std::hex << PatchPointID;
|
||||
LOG_ECMA(DEBUG) << " instructionOffset:0x" << std::hex << InstructionOffset;
|
||||
LOG_ECMA(DEBUG) << " Reserved:0x" << std::hex << Reserved;
|
||||
LOG_ECMA(DEBUG) << " NumLocations:0x" << std::hex << NumLocations;
|
||||
}
|
||||
};
|
||||
|
||||
struct LocationTy {
|
||||
enum class Kind: uint8_t {
|
||||
REGISTER = 1,
|
||||
DIRECT = 2,
|
||||
INDIRECT = 3,
|
||||
CONSTANT = 4,
|
||||
CONSTANTNDEX = 5,
|
||||
};
|
||||
Kind location;
|
||||
uint8_t Reserved_0;
|
||||
uint16_t LocationSize;
|
||||
uint16_t DwarfRegNum;
|
||||
uint16_t Reserved_1;
|
||||
OffsetType OffsetOrSmallConstant;
|
||||
|
||||
std::string PUBLIC_API TypeToString(Kind loc) const;
|
||||
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(DEBUG) << TypeToString(location);
|
||||
LOG_ECMA(DEBUG) << ", size:" << std::dec << LocationSize;
|
||||
LOG_ECMA(DEBUG) << "\tDwarfRegNum:" << DwarfRegNum;
|
||||
LOG_ECMA(DEBUG) << "\t OffsetOrSmallConstant:" << OffsetOrSmallConstant;
|
||||
}
|
||||
};
|
||||
|
||||
struct LiveOutsTy {
|
||||
DwarfRegType DwarfRegNum;
|
||||
uint8_t Reserved;
|
||||
uint8_t SizeinBytes;
|
||||
void Print() const
|
||||
{
|
||||
LOG_ECMA(DEBUG) << " Dwarf RegNum:" << DwarfRegNum;
|
||||
LOG_ECMA(DEBUG) << " Reserved:" << Reserved;
|
||||
LOG_ECMA(DEBUG) << " SizeinBytes:" << SizeinBytes;
|
||||
}
|
||||
};
|
||||
|
||||
struct StkMapRecordTy {
|
||||
struct StkMapRecordHeadTy head;
|
||||
std::vector<struct LocationTy> Locations;
|
||||
std::vector<struct LiveOutsTy> LiveOuts;
|
||||
void Print() const
|
||||
{
|
||||
head.Print();
|
||||
auto size = Locations.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
LOG_ECMA(DEBUG) << " #" << std::dec << i << ":";
|
||||
Locations[i].Print();
|
||||
}
|
||||
size = LiveOuts.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
LOG_ECMA(DEBUG) << " liveOuts[" << i << "] info:";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DataInfo {
|
||||
public:
|
||||
explicit DataInfo(std::unique_ptr<uint8_t[]> data): data_(std::move(data)), offset_(0) {}
|
||||
~DataInfo()
|
||||
{
|
||||
data_.reset();
|
||||
offset_ = 0;
|
||||
}
|
||||
template<class T>
|
||||
T Read()
|
||||
{
|
||||
T t = *reinterpret_cast<const T*>(data_.get() + offset_);
|
||||
offset_ += sizeof(T);
|
||||
return t;
|
||||
}
|
||||
unsigned int GetOffset() const
|
||||
{
|
||||
return offset_;
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> data_ {nullptr};
|
||||
unsigned int offset_ {0};
|
||||
};
|
||||
|
||||
struct LLVMStackMap {
|
||||
struct Header head;
|
||||
std::vector<struct StkSizeRecordTy> StkSizeRecords;
|
||||
std::vector<struct ConstantsTy> Constants;
|
||||
std::vector<struct StkMapRecordTy> StkMapRecord;
|
||||
void Print() const
|
||||
{
|
||||
head.Print();
|
||||
for (size_t i = 0; i < StkSizeRecords.size(); i++) {
|
||||
LOG_ECMA(DEBUG) << "stkSizeRecord[" << i << "] info:";
|
||||
StkSizeRecords[i].Print();
|
||||
}
|
||||
for (size_t i = 0; i < Constants.size(); i++) {
|
||||
LOG_ECMA(DEBUG) << "constants[" << i << "] info:";
|
||||
Constants[i].Print();
|
||||
}
|
||||
for (size_t i = 0; i < StkMapRecord.size(); i++) {
|
||||
LOG_ECMA(DEBUG) << "StkMapRecord[" << i << "] info:";
|
||||
StkMapRecord[i].Print();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class LLVMStackMapParser {
|
||||
public:
|
||||
static LLVMStackMapParser& GetInstance()
|
||||
{
|
||||
static LLVMStackMapParser instance;
|
||||
return instance;
|
||||
}
|
||||
bool PUBLIC_API CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr);
|
||||
bool PUBLIC_API CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr,
|
||||
uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr);
|
||||
void PUBLIC_API Print() const
|
||||
{
|
||||
llvmStackMap_.Print();
|
||||
}
|
||||
const DwarfRegAndOffsetTypeVector *StackMapByAddr(uintptr_t funcAddr) const;
|
||||
bool StackMapByFuncAddrFp(uintptr_t callSiteAddr, uintptr_t frameFp, const RootVisitor &v0,
|
||||
const RootRangeVisitor &v1, panda::ecmascript::ChunkVector<DerivedData> *data,
|
||||
[[maybe_unused]] bool isVerifying) const;
|
||||
private:
|
||||
LLVMStackMapParser()
|
||||
{
|
||||
stackMapAddr_ = nullptr;
|
||||
callSiteInfos_.clear();
|
||||
dataInfo_ = nullptr;
|
||||
}
|
||||
~LLVMStackMapParser()
|
||||
{
|
||||
if (stackMapAddr_) {
|
||||
stackMapAddr_.release();
|
||||
}
|
||||
callSiteInfos_.clear();
|
||||
dataInfo_ = nullptr;
|
||||
}
|
||||
void CalcCallSite();
|
||||
std::unique_ptr<uint8_t[]> stackMapAddr_;
|
||||
struct LLVMStackMap llvmStackMap_;
|
||||
std::unordered_map<uintptr_t, DwarfRegAndOffsetTypeVector> callSiteInfos_;
|
||||
[[maybe_unused]] std::unique_ptr<DataInfo> dataInfo_;
|
||||
};
|
||||
} // namespace kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H
|
||||
@@ -1,277 +1,320 @@
|
||||
/*
|
||||
* 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 "llvm_codegen.h"
|
||||
#include <vector>
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "stub_descriptor.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/CodeGen/BuiltinGCs.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IRReader/IRReader.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/llvm_stackmap_parser.h"
|
||||
#include "llvm-c/Analysis.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/Disassembler.h"
|
||||
#include "llvm-c/DisassemblerTypes.h"
|
||||
#include "llvm-c/Target.h"
|
||||
#include "llvm-c/Transforms/PassManagerBuilder.h"
|
||||
#include "llvm-c/Transforms/Scalar.h"
|
||||
|
||||
using namespace panda::ecmascript;
|
||||
namespace kungfu {
|
||||
void LLVMCodeGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, int index)
|
||||
{
|
||||
auto function = module_->GetStubFunction(index);
|
||||
|
||||
LLVMIRBuilder builder(&graph, circuit, module_, function);
|
||||
builder.Build();
|
||||
}
|
||||
|
||||
void LLVMModuleAssembler::AssembleModule()
|
||||
{
|
||||
assembler_.Run();
|
||||
}
|
||||
|
||||
void LLVMModuleAssembler::AssembleStubModule(StubModule *module)
|
||||
{
|
||||
auto codeBuff = reinterpret_cast<uintptr_t>(assembler_.GetCodeBuffer());
|
||||
auto engine = assembler_.GetEngine();
|
||||
std::map<uint64_t, std::string> addr2name;
|
||||
for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) {
|
||||
auto stubfunction = stubmodule_->GetStubFunction(i);
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << " AssembleStubModule :" << i << " th " << std::endl;
|
||||
#endif
|
||||
if (stubfunction != nullptr) {
|
||||
uintptr_t stubEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, stubfunction));
|
||||
module->SetStubEntry(i, stubEntry - codeBuff);
|
||||
addr2name[stubEntry] = FastStubDescriptors::GetInstance().GetStubDescriptor(i)->GetName();
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << "name : " << addr2name[codeBuff] << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
module->SetHostCodeSectionAddr(codeBuff);
|
||||
// stackmaps ptr and size
|
||||
module->SetStackMapAddr(reinterpret_cast<uintptr_t>(assembler_.GetStackMapsSection()));
|
||||
module->SetStackMapSize(assembler_.GetStackMapsSize());
|
||||
#ifndef NDEBUG
|
||||
assembler_.Disassemble(addr2name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t *RoundTripAllocateCodeSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
|
||||
[[maybe_unused]] unsigned sectionID, const char *sectionName)
|
||||
{
|
||||
LOG_ECMA(INFO) << "RoundTripAllocateCodeSection object " << object << " - ";
|
||||
struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
|
||||
uint8_t *addr = state.AllocaCodeSection(size, sectionName);
|
||||
LOG_ECMA(INFO) << "RoundTripAllocateCodeSection addr:" << std::hex << reinterpret_cast<std::uintptr_t>(addr) <<
|
||||
addr << " size:0x" << size << " + ";
|
||||
return addr;
|
||||
}
|
||||
|
||||
static uint8_t *RoundTripAllocateDataSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
|
||||
[[maybe_unused]] unsigned sectionID, const char *sectionName,
|
||||
[[maybe_unused]] LLVMBool isReadOnly)
|
||||
{
|
||||
struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
|
||||
return state.AllocaDataSection(size, sectionName);
|
||||
}
|
||||
|
||||
static LLVMBool RoundTripFinalizeMemory(void *object, [[maybe_unused]] char **errMsg)
|
||||
{
|
||||
LOG_ECMA(INFO) << "RoundTripFinalizeMemory object " << object << " - ";
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void RoundTripDestroy(void *object)
|
||||
{
|
||||
LOG_ECMA(INFO) << "RoundTripDestroy object " << object << " - ";
|
||||
}
|
||||
|
||||
void LLVMAssembler::UseRoundTripSectionMemoryManager()
|
||||
{
|
||||
auto sectionMemoryManager = std::make_unique<llvm::SectionMemoryManager>();
|
||||
options_.MCJMM =
|
||||
LLVMCreateSimpleMCJITMemoryManager(&codeInfo_, RoundTripAllocateCodeSection,
|
||||
RoundTripAllocateDataSection, RoundTripFinalizeMemory, RoundTripDestroy);
|
||||
}
|
||||
|
||||
bool LLVMAssembler::BuildMCJITEngine()
|
||||
{
|
||||
LOG_ECMA(INFO) << " BuildMCJITEngine - ";
|
||||
LLVMBool ret = LLVMCreateMCJITCompilerForModule(&engine_, module_, &options_, sizeof(options_), &error_);
|
||||
if (ret) {
|
||||
LOG_ECMA(ERROR) << "error_ : " << error_;
|
||||
return false;
|
||||
}
|
||||
LOG_ECMA(INFO) << " BuildMCJITEngine + ";
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLVMAssembler::BuildAndRunPasses() const
|
||||
{
|
||||
LOG_ECMA(INFO) << "BuildAndRunPasses - ";
|
||||
LLVMPassManagerRef pm = LLVMCreatePassManager();
|
||||
LLVMAddConstantPropagationPass(pm);
|
||||
LLVMAddInstructionCombiningPass(pm);
|
||||
llvm::unwrap(pm)->add(llvm::createRewriteStatepointsForGCLegacyPass());
|
||||
#ifndef NDEBUG
|
||||
char *info = LLVMPrintModuleToString(module_);
|
||||
LOG_ECMA(INFO) << "Current Module: " << info;
|
||||
LLVMDumpModule(module_);
|
||||
LLVMDisposeMessage(info);
|
||||
#endif
|
||||
LLVMRunPassManager(pm, module_);
|
||||
LLVMDisposePassManager(pm);
|
||||
LOG_ECMA(INFO) << "BuildAndRunPasses + ";
|
||||
}
|
||||
|
||||
LLVMAssembler::LLVMAssembler(LLVMModuleRef module, const char* triple): module_(module), engine_(nullptr),
|
||||
hostTriple_(triple), error_(nullptr)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
LLVMAssembler::~LLVMAssembler()
|
||||
{
|
||||
module_ = nullptr;
|
||||
if (engine_ != nullptr) {
|
||||
LLVMDisposeExecutionEngine(engine_);
|
||||
}
|
||||
hostTriple_ = "";
|
||||
error_ = nullptr;
|
||||
}
|
||||
|
||||
void LLVMAssembler::Run()
|
||||
{
|
||||
char *error = nullptr;
|
||||
LLVMVerifyModule(module_, LLVMAbortProcessAction, &error);
|
||||
LLVMDisposeMessage(error);
|
||||
UseRoundTripSectionMemoryManager();
|
||||
if (!BuildMCJITEngine()) {
|
||||
return;
|
||||
}
|
||||
BuildAndRunPasses();
|
||||
}
|
||||
|
||||
void LLVMAssembler::Initialize()
|
||||
{
|
||||
if (hostTriple_.compare(AMD64_TRIPLE) == 0) {
|
||||
LLVMInitializeX86TargetInfo();
|
||||
LLVMInitializeX86TargetMC();
|
||||
LLVMInitializeX86Disassembler();
|
||||
/* this method must be called, ohterwise "Target does not support MC emission" */
|
||||
LLVMInitializeX86AsmPrinter();
|
||||
LLVMInitializeX86AsmParser();
|
||||
LLVMInitializeX86Target();
|
||||
} else if (hostTriple_.compare(ARM64_TRIPLE) == 0) {
|
||||
LLVMInitializeAArch64TargetInfo();
|
||||
LLVMInitializeAArch64TargetMC();
|
||||
LLVMInitializeAArch64Disassembler();
|
||||
LLVMInitializeAArch64AsmPrinter();
|
||||
LLVMInitializeAArch64AsmParser();
|
||||
LLVMInitializeAArch64Target();
|
||||
} else if (hostTriple_.compare(ARM32_TRIPLE) == 0) {
|
||||
LLVMInitializeARMTargetInfo();
|
||||
LLVMInitializeARMTargetMC();
|
||||
LLVMInitializeARMDisassembler();
|
||||
LLVMInitializeARMAsmPrinter();
|
||||
LLVMInitializeARMAsmParser();
|
||||
LLVMInitializeARMTarget();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
llvm::linkAllBuiltinGCs();
|
||||
LLVMInitializeMCJITCompilerOptions(&options_, sizeof(options_));
|
||||
options_.OptLevel = 2; // opt level 2
|
||||
// Just ensure that this field still exists.
|
||||
options_.NoFramePointerElim = true;
|
||||
}
|
||||
|
||||
static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_unused]] uint64_t referenceValue,
|
||||
uint64_t *referenceType, [[maybe_unused]]uint64_t referencePC,
|
||||
[[maybe_unused]] const char **referenceName)
|
||||
{
|
||||
*referenceType = LLVMDisassembler_ReferenceType_InOut_None;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LLVMAssembler::Disassemble(std::map<uint64_t, std::string> addr2name) const
|
||||
{
|
||||
LLVMDisasmContextRef dcr = LLVMCreateDisasm(hostTriple_.c_str(), nullptr, 0, nullptr, SymbolLookupCallback);
|
||||
std::cout << "========================================================================" << std::endl;
|
||||
for (auto it : codeInfo_.GetCodeInfo()) {
|
||||
uint8_t *byteSp;
|
||||
uintptr_t numBytes;
|
||||
byteSp = it.first;
|
||||
numBytes = it.second;
|
||||
std::cout << " byteSp:" << std::hex << reinterpret_cast<std::uintptr_t>(byteSp) << " numBytes:0x" << numBytes
|
||||
<< std::endl;
|
||||
|
||||
unsigned pc = 0;
|
||||
const char outStringSize = 100;
|
||||
char outString[outStringSize];
|
||||
while (numBytes != 0) {
|
||||
size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize);
|
||||
if (InstSize == 0) {
|
||||
std::cerr.fill('0');
|
||||
std::cerr.width(8); // 8: fixed hex print width
|
||||
std::cerr << std::hex << pc << ":";
|
||||
std::cerr.width(8); // 8: fixed hex print width
|
||||
std::cerr << std::hex << *reinterpret_cast<uint32_t *>(byteSp) << "maybe constant" << std::endl;
|
||||
pc += 4; // 4 pc length
|
||||
byteSp += 4; // 4 sp offset
|
||||
numBytes -= 4; // 4 num bytes
|
||||
}
|
||||
uint64_t addr = reinterpret_cast<uint64_t>(byteSp);
|
||||
if (addr2name.find(addr) != addr2name.end()) {
|
||||
std::cout << addr2name[addr].c_str() << ":" << std::endl;
|
||||
}
|
||||
std::cerr.fill('0');
|
||||
std::cerr.width(8); // 8: fixed hex print width
|
||||
std::cerr << std::hex << pc << ":";
|
||||
std::cerr.width(8); // 8: fixed hex print width
|
||||
std::cerr << std::hex << *reinterpret_cast<uint32_t *>(byteSp) << " " << outString << std::endl;
|
||||
pc += InstSize;
|
||||
byteSp += InstSize;
|
||||
numBytes -= InstSize;
|
||||
}
|
||||
}
|
||||
std::cout << "========================================================================" << std::endl;
|
||||
LLVMDisasmDispose(dcr);
|
||||
}
|
||||
} // namespace kungfu
|
||||
/*
|
||||
* 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 "llvm_codegen.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "ecmascript/compiler/compiler_macros.h"
|
||||
#include "ecmascript/compiler/triple.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "llvm-c/Analysis.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/Disassembler.h"
|
||||
#include "llvm-c/DisassemblerTypes.h"
|
||||
#include "llvm-c/Target.h"
|
||||
#include "llvm-c/Transforms/PassManagerBuilder.h"
|
||||
#include "llvm-c/Transforms/Scalar.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/CodeGen/BuiltinGCs.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IRReader/IRReader.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/llvm_stackmap_parser.h"
|
||||
#include "stub_descriptor.h"
|
||||
|
||||
using namespace panda::ecmascript;
|
||||
namespace kungfu {
|
||||
void LLVMCodeGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, int index)
|
||||
{
|
||||
auto function = module_->GetStubFunction(index);
|
||||
|
||||
LLVMIRBuilder builder(&graph, circuit, module_, function, TripleConst::GetLLVMAmd64Triple());
|
||||
builder.Build();
|
||||
}
|
||||
|
||||
void LLVMAarch64CodeGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, int index)
|
||||
{
|
||||
auto function = module_->GetStubFunction(index);
|
||||
|
||||
LLVMIRBuilder builder(&graph, circuit, module_, function, TripleConst::GetLLVMArm64Triple());
|
||||
builder.Build();
|
||||
}
|
||||
|
||||
void LLVMArm32CodeGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, int index)
|
||||
{
|
||||
auto function = module_->GetStubFunction(index);
|
||||
|
||||
LLVMIRBuilder builder(&graph, circuit, module_, function, TripleConst::GetLLVMArm32Triple());
|
||||
builder.Build();
|
||||
}
|
||||
|
||||
void LLVMModuleAssembler::AssembleModule()
|
||||
{
|
||||
assembler_.Run();
|
||||
}
|
||||
|
||||
void LLVMModuleAssembler::AssembleStubModule(StubModule *module)
|
||||
{
|
||||
auto codeBuff = reinterpret_cast<uintptr_t>(assembler_.GetCodeBuffer());
|
||||
auto engine = assembler_.GetEngine();
|
||||
std::map<uint64_t, std::string> addr2name;
|
||||
for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) {
|
||||
auto stubfunction = stubmodule_->GetStubFunction(i);
|
||||
#ifndef NDEBUG
|
||||
COMPILER_LOG(DEBUG) << " AssembleStubModule :" << i << " th " << std::endl;
|
||||
#endif
|
||||
if (stubfunction != nullptr) {
|
||||
uintptr_t stubEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, stubfunction));
|
||||
module->SetStubEntry(i, stubEntry - codeBuff);
|
||||
addr2name[stubEntry] = FastStubDescriptors::GetInstance().GetStubDescriptor(i)->GetName();
|
||||
#ifndef NDEBUG
|
||||
COMPILER_LOG(DEBUG) << "name : " << addr2name[codeBuff] << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
module->SetHostCodeSectionAddr(codeBuff);
|
||||
// stackmaps ptr and size
|
||||
module->SetStackMapAddr(reinterpret_cast<uintptr_t>(assembler_.GetStackMapsSection()));
|
||||
module->SetStackMapSize(assembler_.GetStackMapsSize());
|
||||
#ifndef NDEBUG
|
||||
assembler_.Disassemble(addr2name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t *RoundTripAllocateCodeSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
|
||||
[[maybe_unused]] unsigned sectionID, const char *sectionName)
|
||||
{
|
||||
COMPILER_LOG(DEBUG) << "RoundTripAllocateCodeSection object " << object << " - ";
|
||||
struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
|
||||
uint8_t *addr = state.AllocaCodeSection(size, sectionName);
|
||||
COMPILER_LOG(DEBUG) << "RoundTripAllocateCodeSection addr:" << std::hex <<
|
||||
reinterpret_cast<std::uintptr_t>(addr) << addr << " size:0x" << size << " + ";
|
||||
return addr;
|
||||
}
|
||||
|
||||
static uint8_t *RoundTripAllocateDataSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
|
||||
[[maybe_unused]] unsigned sectionID, const char *sectionName,
|
||||
[[maybe_unused]] LLVMBool isReadOnly)
|
||||
{
|
||||
struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
|
||||
return state.AllocaDataSection(size, sectionName);
|
||||
}
|
||||
|
||||
static LLVMBool RoundTripFinalizeMemory(void *object, [[maybe_unused]] char **errMsg)
|
||||
{
|
||||
COMPILER_LOG(DEBUG) << "RoundTripFinalizeMemory object " << object << " - ";
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void RoundTripDestroy(void *object)
|
||||
{
|
||||
COMPILER_LOG(DEBUG) << "RoundTripDestroy object " << object << " - ";
|
||||
}
|
||||
|
||||
void LLVMAssembler::UseRoundTripSectionMemoryManager()
|
||||
{
|
||||
auto sectionMemoryManager = std::make_unique<llvm::SectionMemoryManager>();
|
||||
options_.MCJMM =
|
||||
LLVMCreateSimpleMCJITMemoryManager(&codeInfo_, RoundTripAllocateCodeSection,
|
||||
RoundTripAllocateDataSection, RoundTripFinalizeMemory, RoundTripDestroy);
|
||||
}
|
||||
|
||||
bool LLVMAssembler::BuildMCJITEngine()
|
||||
{
|
||||
COMPILER_LOG(DEBUG) << " BuildMCJITEngine - ";
|
||||
LLVMBool ret = LLVMCreateMCJITCompilerForModule(&engine_, module_, &options_, sizeof(options_), &error_);
|
||||
if (ret) {
|
||||
LOG_ECMA(FATAL) << "error_ : " << error_;
|
||||
return false;
|
||||
}
|
||||
COMPILER_LOG(DEBUG) << " BuildMCJITEngine + ";
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLVMAssembler::BuildAndRunPasses() const
|
||||
{
|
||||
COMPILER_LOG(DEBUG) << "BuildAndRunPasses - ";
|
||||
LLVMPassManagerBuilderRef pmBuilder = LLVMPassManagerBuilderCreate();
|
||||
LLVMPassManagerBuilderSetOptLevel(pmBuilder, 3); // using O3 optimization level
|
||||
LLVMPassManagerBuilderSetSizeLevel(pmBuilder, 0);
|
||||
LLVMPassManagerRef funcPass = LLVMCreateFunctionPassManagerForModule(module_);
|
||||
LLVMPassManagerRef modPass = LLVMCreatePassManager();
|
||||
LLVMPassManagerBuilderPopulateFunctionPassManager(pmBuilder, funcPass);
|
||||
llvm::unwrap(modPass)->add(llvm::createRewriteStatepointsForGCLegacyPass());
|
||||
LLVMPassManagerBuilderPopulateModulePassManager(pmBuilder, modPass);
|
||||
LLVMPassManagerBuilderDispose(pmBuilder);
|
||||
LLVMInitializeFunctionPassManager(funcPass);
|
||||
for (LLVMValueRef fn = LLVMGetFirstFunction(module_); fn; fn = LLVMGetNextFunction(fn)) {
|
||||
LLVMRunFunctionPassManager(funcPass, fn);
|
||||
}
|
||||
LLVMFinalizeFunctionPassManager(funcPass);
|
||||
LLVMRunPassManager(modPass, module_);
|
||||
LLVMDisposePassManager(funcPass);
|
||||
LLVMDisposePassManager(modPass);
|
||||
COMPILER_LOG(DEBUG) << "BuildAndRunPasses + ";
|
||||
}
|
||||
|
||||
LLVMAssembler::LLVMAssembler(LLVMModuleRef module, const char* triple)
|
||||
: module_(module), triple_(triple)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
LLVMAssembler::~LLVMAssembler()
|
||||
{
|
||||
if (engine_ != nullptr) {
|
||||
if (module_ != nullptr) {
|
||||
char *error = nullptr;
|
||||
LLVMRemoveModule(engine_, module_, &module_, &error);
|
||||
if (error != nullptr) {
|
||||
LLVMDisposeMessage(error);
|
||||
}
|
||||
}
|
||||
LLVMDisposeExecutionEngine(engine_);
|
||||
engine_ = nullptr;
|
||||
}
|
||||
module_ = nullptr;
|
||||
error_ = nullptr;
|
||||
}
|
||||
|
||||
void LLVMAssembler::Run()
|
||||
{
|
||||
char *error = nullptr;
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
char *info = LLVMPrintModuleToString(module_);
|
||||
COMPILER_LOG(INFO) << "Current Module: " << info;
|
||||
LLVMDisposeMessage(info);
|
||||
LLVMDumpModule(module_);
|
||||
#endif
|
||||
LLVMPrintModuleToFile(module_, "stub.ll", &error);
|
||||
LLVMVerifyModule(module_, LLVMAbortProcessAction, &error);
|
||||
LLVMDisposeMessage(error);
|
||||
UseRoundTripSectionMemoryManager();
|
||||
if (!BuildMCJITEngine()) {
|
||||
return;
|
||||
}
|
||||
BuildAndRunPasses();
|
||||
LLVMPrintModuleToFile(module_, "opt_stub.ll", &error);
|
||||
}
|
||||
|
||||
void LLVMAssembler::Initialize()
|
||||
{
|
||||
if (triple_ == TripleConst::GetLLVMAmd64Triple()) {
|
||||
LLVMInitializeX86TargetInfo();
|
||||
LLVMInitializeX86TargetMC();
|
||||
LLVMInitializeX86Disassembler();
|
||||
/* this method must be called, ohterwise "Target does not support MC emission" */
|
||||
LLVMInitializeX86AsmPrinter();
|
||||
LLVMInitializeX86AsmParser();
|
||||
LLVMInitializeX86Target();
|
||||
} else if (triple_ == TripleConst::GetLLVMArm64Triple()) {
|
||||
LLVMInitializeAArch64TargetInfo();
|
||||
LLVMInitializeAArch64TargetMC();
|
||||
LLVMInitializeAArch64Disassembler();
|
||||
LLVMInitializeAArch64AsmPrinter();
|
||||
LLVMInitializeAArch64AsmParser();
|
||||
LLVMInitializeAArch64Target();
|
||||
} else if (triple_ == TripleConst::GetLLVMArm32Triple()) {
|
||||
LLVMInitializeARMTargetInfo();
|
||||
LLVMInitializeARMTargetMC();
|
||||
LLVMInitializeARMDisassembler();
|
||||
LLVMInitializeARMAsmPrinter();
|
||||
LLVMInitializeARMAsmParser();
|
||||
LLVMInitializeARMTarget();
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
llvm::linkAllBuiltinGCs();
|
||||
LLVMInitializeMCJITCompilerOptions(&options_, sizeof(options_));
|
||||
options_.OptLevel = 2; // opt level 2
|
||||
// Just ensure that this field still exists.
|
||||
options_.NoFramePointerElim = true;
|
||||
}
|
||||
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_unused]] uint64_t referenceValue,
|
||||
uint64_t *referenceType, [[maybe_unused]]uint64_t referencePC,
|
||||
[[maybe_unused]] const char **referenceName)
|
||||
{
|
||||
*referenceType = LLVMDisassembler_ReferenceType_InOut_None;
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void LLVMAssembler::Disassemble(std::map<uint64_t, std::string> addr2name) const
|
||||
{
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
LLVMDisasmContextRef dcr = LLVMCreateDisasm(triple_, nullptr, 0, nullptr, SymbolLookupCallback);
|
||||
std::cout << "========================================================================" << std::endl;
|
||||
for (auto it : codeInfo_.GetCodeInfo()) {
|
||||
uint8_t *byteSp;
|
||||
uintptr_t numBytes;
|
||||
byteSp = it.first;
|
||||
numBytes = it.second;
|
||||
std::cout << " byteSp:" << std::hex << reinterpret_cast<std::uintptr_t>(byteSp) << " numBytes:0x" << numBytes
|
||||
<< std::endl;
|
||||
|
||||
unsigned pc = 0;
|
||||
const char outStringSize = 100;
|
||||
char outString[outStringSize];
|
||||
while (numBytes != 0) {
|
||||
size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize);
|
||||
if (InstSize == 0) {
|
||||
std::cerr.fill('0');
|
||||
std::cerr.width(8); // 8:fixed hex print width
|
||||
std::cerr << std::hex << pc << ":";
|
||||
std::cerr.width(8); // 8:fixed hex print width
|
||||
std::cerr << std::hex << *reinterpret_cast<uint32_t *>(byteSp) << "maybe constant" << std::endl;
|
||||
pc += 4; // 4 pc length
|
||||
byteSp += 4; // 4 sp offset
|
||||
numBytes -= 4; // 4 num bytes
|
||||
}
|
||||
uint64_t addr = reinterpret_cast<uint64_t>(byteSp);
|
||||
if (addr2name.find(addr) != addr2name.end()) {
|
||||
std::cout << addr2name[addr].c_str() << ":" << std::endl;
|
||||
}
|
||||
std::cerr.fill('0');
|
||||
std::cerr.width(8); // 8:fixed hex print width
|
||||
std::cerr << std::hex << pc << ":";
|
||||
std::cerr.width(8); // 8:fixed hex print width
|
||||
std::cerr << std::hex << *reinterpret_cast<uint32_t *>(byteSp) << " " << outString << std::endl;
|
||||
pc += InstSize;
|
||||
byteSp += InstSize;
|
||||
numBytes -= InstSize;
|
||||
}
|
||||
}
|
||||
std::cout << "========================================================================" << std::endl;
|
||||
LLVMDisasmDispose(dcr);
|
||||
#endif
|
||||
}
|
||||
} // namespace kungfu
|
||||
|
||||
@@ -27,18 +27,18 @@
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "ecmascript/stub_module.h"
|
||||
#include "llvm-c/Types.h"
|
||||
#include "llvm-c/Analysis.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/ExecutionEngine.h"
|
||||
#include "llvm-c/Target.h"
|
||||
#include "llvm-c/Transforms/PassManagerBuilder.h"
|
||||
#include "llvm-c/Transforms/Scalar.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm-c/Types.h"
|
||||
#include "llvm/ExecutionEngine/Interpreter.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
|
||||
namespace kungfu {
|
||||
struct CodeInfo {
|
||||
@@ -51,11 +51,20 @@ struct CodeInfo {
|
||||
static constexpr int prot = PROT_READ | PROT_WRITE | PROT_EXEC; // NOLINT(hicpp-signed-bitwise)
|
||||
static constexpr int flags = MAP_ANONYMOUS | MAP_SHARED; // NOLINT(hicpp-signed-bitwise)
|
||||
machineCode_ = static_cast<uint8_t *>(mmap(nullptr, MAX_MACHINE_CODE_SIZE, prot, flags, -1, 0));
|
||||
if (machineCode_ == reinterpret_cast<uint8_t *>(-1)) {
|
||||
machineCode_ = nullptr;
|
||||
}
|
||||
if (machineCode_ != nullptr) {
|
||||
ASAN_UNPOISON_MEMORY_REGION(machineCode_, MAX_MACHINE_CODE_SIZE);
|
||||
}
|
||||
}
|
||||
~CodeInfo()
|
||||
{
|
||||
Reset();
|
||||
munmap(machineCode_, MAX_MACHINE_CODE_SIZE);
|
||||
if (machineCode_ != nullptr) {
|
||||
ASAN_POISON_MEMORY_REGION(machineCode_, MAX_MACHINE_CODE_SIZE);
|
||||
munmap(machineCode_, MAX_MACHINE_CODE_SIZE);
|
||||
}
|
||||
machineCode_ = nullptr;
|
||||
}
|
||||
uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName)
|
||||
@@ -67,11 +76,8 @@ struct CodeInfo {
|
||||
return nullptr;
|
||||
}
|
||||
LOG_ECMA(INFO) << "AllocaCodeSection size:" << size;
|
||||
std::vector<uint8_t> codeBuffer(machineCode_[codeBufferPos_], size);
|
||||
LOG_ECMA(INFO) << " codeBuffer size: " << codeBuffer.size();
|
||||
codeSectionNames_.push_back(sectionName);
|
||||
addr = machineCode_ + codeBufferPos_;
|
||||
LOG_ECMA(INFO) << "AllocaCodeSection addr:" << std::hex << reinterpret_cast<std::uintptr_t>(addr);
|
||||
codeInfo_.push_back({addr, size});
|
||||
codeBufferPos_ += size;
|
||||
return addr;
|
||||
@@ -85,7 +91,7 @@ struct CodeInfo {
|
||||
dataSectionNames_.push_back(sectionName);
|
||||
addr = static_cast<uint8_t *>(dataSectionList_.back().data());
|
||||
if (!strcmp(sectionName, ".llvm_stackmaps")) {
|
||||
LOG_ECMA(INFO) << "llvm_stackmaps : " << addr << " size:" << size << std::endl;
|
||||
LOG_ECMA(INFO) << "llvm_stackmaps : " << addr << " size:" << size;
|
||||
stackMapsSection_ = addr;
|
||||
stackMapsSize_ = size;
|
||||
}
|
||||
@@ -171,9 +177,6 @@ public:
|
||||
{
|
||||
return LLVMGetPointerToGlobal(engine_, function);
|
||||
}
|
||||
const char *AMD64_TRIPLE = "x86_64-unknown-linux-gnu";
|
||||
const char *ARM64_TRIPLE = "aarch64-unknown-linux-gnu";
|
||||
const char *ARM32_TRIPLE = "arm-unknown-linux-gnu";
|
||||
private:
|
||||
void UseRoundTripSectionMemoryManager();
|
||||
bool BuildMCJITEngine();
|
||||
@@ -182,12 +185,12 @@ private:
|
||||
void Initialize();
|
||||
void InitMember();
|
||||
|
||||
LLVMMCJITCompilerOptions options_;
|
||||
LLVMMCJITCompilerOptions options_ {};
|
||||
LLVMModuleRef module_;
|
||||
LLVMExecutionEngineRef engine_;
|
||||
std::string hostTriple_;
|
||||
char *error_;
|
||||
struct CodeInfo codeInfo_;
|
||||
LLVMExecutionEngineRef engine_ {nullptr};
|
||||
const char *triple_;
|
||||
char *error_ {nullptr};
|
||||
struct CodeInfo codeInfo_ {};
|
||||
};
|
||||
|
||||
class LLVMCodeGeneratorImpl : public CodeGeneratorImpl {
|
||||
@@ -200,6 +203,26 @@ private:
|
||||
LLVMStubModule *module_;
|
||||
};
|
||||
|
||||
class LLVMAarch64CodeGeneratorImpl : public CodeGeneratorImpl {
|
||||
public:
|
||||
explicit LLVMAarch64CodeGeneratorImpl(LLVMStubModule *module) : module_(module) {}
|
||||
~LLVMAarch64CodeGeneratorImpl() = default;
|
||||
void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, int index) override;
|
||||
|
||||
private:
|
||||
LLVMStubModule *module_;
|
||||
};
|
||||
|
||||
class LLVMArm32CodeGeneratorImpl : public CodeGeneratorImpl {
|
||||
public:
|
||||
explicit LLVMArm32CodeGeneratorImpl(LLVMStubModule *module) : module_(module) {}
|
||||
~LLVMArm32CodeGeneratorImpl() = default;
|
||||
void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, int index) override;
|
||||
|
||||
private:
|
||||
LLVMStubModule *module_;
|
||||
};
|
||||
|
||||
class LLVMModuleAssembler {
|
||||
public:
|
||||
explicit LLVMModuleAssembler(LLVMStubModule *module, const char* triple)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,8 +22,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "ecmascript/compiler/circuit.h"
|
||||
#include "ecmascript/compiler/stub_descriptor.h"
|
||||
#include "ecmascript/compiler/gate.h"
|
||||
#include "ecmascript/compiler/stub_descriptor.h"
|
||||
#include "ecmascript/compiler/triple.h"
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/Types.h"
|
||||
|
||||
@@ -32,7 +33,7 @@ using OperandsVector = std::set<int>;
|
||||
class BasicBlock;
|
||||
using BasicBlockMap = std::map<int, std::unique_ptr<BasicBlock>>;
|
||||
class LLVMIRBuilder;
|
||||
typedef void (LLVMIRBuilder::*HandleType)(AddrShift gate);
|
||||
using HandleType = void(LLVMIRBuilder::*)(GateRef gate);
|
||||
|
||||
enum class MachineRep {
|
||||
K_NONE,
|
||||
@@ -44,7 +45,9 @@ enum class MachineRep {
|
||||
// FP representations must be last, and in order of increasing size.
|
||||
K_FLOAT32,
|
||||
K_FLOAT64,
|
||||
K_SIMD128
|
||||
K_SIMD128,
|
||||
K_PTR_1, // Tagged Pointer
|
||||
K_META,
|
||||
};
|
||||
|
||||
class BasicBlock {
|
||||
@@ -91,7 +94,7 @@ private:
|
||||
|
||||
struct NotMergedPhiDesc {
|
||||
BasicBlock *pred;
|
||||
AddrShift operand;
|
||||
GateRef operand;
|
||||
LLVMValueRef phi;
|
||||
};
|
||||
|
||||
@@ -105,8 +108,8 @@ struct LLVMTFBuilderBasicBlockImpl {
|
||||
|
||||
class LLVMStubModule {
|
||||
public:
|
||||
explicit LLVMStubModule(const char *name, const char *triple);
|
||||
~LLVMStubModule() = default;
|
||||
LLVMStubModule(const char *name, const char *hostTriple);
|
||||
~LLVMStubModule();
|
||||
|
||||
void Initialize();
|
||||
|
||||
@@ -129,8 +132,17 @@ public:
|
||||
|
||||
LLVMValueRef GetTestFunction(uint32_t index)
|
||||
{
|
||||
ASSERT(index - TEST_FUNCTION_OFFSET < MAX_TEST_FUNCTION_COUNT);
|
||||
return testFunctions_[index - TEST_FUNCTION_OFFSET];
|
||||
#ifndef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
ASSERT(index - TEST_FUNCTION_OFFSET < MAX_TEST_FUNCTION_COUNT);
|
||||
return testFunctions_[index - TEST_FUNCTION_OFFSET];
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *GetTargetTriple() const
|
||||
{
|
||||
return triple_;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -142,58 +154,63 @@ private:
|
||||
static constexpr uint32_t TEST_FUNCTION_OFFSET = kungfu::TEST_FUNC_BEGIN + 1;
|
||||
std::array<LLVMValueRef, FAST_STUB_MAXCOUNT> stubFunctions_ {nullptr};
|
||||
std::array<LLVMTypeRef, MAX_STUB_FUNCTION_COUNT> stubFunctionType_ {nullptr};
|
||||
#ifndef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
std::array<LLVMValueRef, MAX_TEST_FUNCTION_COUNT> testFunctions_ {nullptr};
|
||||
#endif
|
||||
LLVMModuleRef module_;
|
||||
const char *triple_;
|
||||
};
|
||||
|
||||
#define OPCODES(V) \
|
||||
V(Call, (AddrShift gate, const std::vector<AddrShift> &inList)) \
|
||||
V(Alloca, (AddrShift gate)) \
|
||||
V(Call, (GateRef gate, const std::vector<GateRef> &inList)) \
|
||||
V(Alloca, (GateRef gate)) \
|
||||
V(Block, (int id, const OperandsVector &predecessors)) \
|
||||
V(Goto, (int block, int bbout)) \
|
||||
V(Parameter, (AddrShift gate) const ) \
|
||||
V(Int32Constant, (AddrShift gate, int32_t value) const ) \
|
||||
V(Int64Constant, (AddrShift gate, int64_t value) const ) \
|
||||
V(Float64Constant, (AddrShift gate, double value) const ) \
|
||||
V(ZExtInt, (AddrShift gate, AddrShift e1, MachineRep rep) const ) \
|
||||
V(SExtInt, (AddrShift gate, AddrShift e1, MachineRep rep) const ) \
|
||||
V(Load, (AddrShift gate, MachineRep rep, AddrShift base) const ) \
|
||||
V(Store, (AddrShift gate, MachineRep rep, AddrShift base, AddrShift value) const ) \
|
||||
V(IntRev, (AddrShift gate, AddrShift e1) const ) \
|
||||
V(IntAdd, (AddrShift gate, AddrShift e1, AddrShift e2, MachineRep rep) const ) \
|
||||
V(FloatAdd, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(FloatSub, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(FloatMul, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(FloatDiv, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(IntSub, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(IntMul, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(IntOr, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(IntAnd, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(IntXor, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(IntLsr, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(Int32LessThanOrEqual, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \
|
||||
V(IntOrUintCmp, (AddrShift gate, AddrShift e1, AddrShift e2, LLVMIntPredicate opcode) const ) \
|
||||
V(FloatOrDoubleCmp, (AddrShift gate, AddrShift e1, AddrShift e2, LLVMRealPredicate opcode) const ) \
|
||||
V(Branch, (AddrShift gate, AddrShift cmp, AddrShift btrue, AddrShift bfalse)) \
|
||||
V(Switch, (AddrShift gate, AddrShift input, const std::vector<AddrShift> &outList)) \
|
||||
V(SwitchCase, (AddrShift gate, AddrShift switchBranch, AddrShift out)) \
|
||||
V(Phi, (AddrShift gate, const std::vector<AddrShift> &srcGates, MachineRep rep)) \
|
||||
V(Return, (AddrShift gate, AddrShift popCount, const std::vector<AddrShift> &operands) const ) \
|
||||
V(CastIntXToIntY, (AddrShift gate, AddrShift e1, MachineRep rep) const ) \
|
||||
V(ChangeInt32ToDouble, (AddrShift gate, AddrShift e1) const ) \
|
||||
V(ChangeDoubleToInt32, (AddrShift gate, AddrShift e1) const ) \
|
||||
V(CastInt64ToDouble, (AddrShift gate, AddrShift e1) const ) \
|
||||
V(CastDoubleToInt, (AddrShift gate, AddrShift e1) const ) \
|
||||
V(CastInt64ToPointer, (AddrShift gate, AddrShift e1) const ) \
|
||||
V(IntLsl, (AddrShift gate, AddrShift e1, AddrShift e2) const) \
|
||||
V(IntMod, (AddrShift gate, AddrShift e1, AddrShift e2) const) \
|
||||
V(FloatMod, (AddrShift gate, AddrShift e1, AddrShift e2) const) \
|
||||
|
||||
V(Parameter, (GateRef gate) const) \
|
||||
V(Int32Constant, (GateRef gate, int32_t value) const) \
|
||||
V(Int64Constant, (GateRef gate, int64_t value) const) \
|
||||
V(Float64Constant, (GateRef gate, double value) const) \
|
||||
V(ZExtInt, (GateRef gate, GateRef e1) const) \
|
||||
V(SExtInt, (GateRef gate, GateRef e1) const) \
|
||||
V(Load, (GateRef gate, GateRef base) const) \
|
||||
V(Store, (GateRef gate, GateRef base, GateRef value) const) \
|
||||
V(IntRev, (GateRef gate, GateRef e1) const) \
|
||||
V(IntAdd, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(FloatAdd, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(FloatSub, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(FloatMul, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(FloatDiv, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntSub, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntMul, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntOr, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntAnd, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntXor, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntLsr, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(Int32LessThanOrEqual, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntOrUintCmp, (GateRef gate, GateRef e1, GateRef e2, LLVMIntPredicate opcode) const) \
|
||||
V(FloatOrDoubleCmp, (GateRef gate, GateRef e1, GateRef e2, LLVMRealPredicate opcode) const) \
|
||||
V(Branch, (GateRef gate, GateRef cmp, GateRef btrue, GateRef bfalse)) \
|
||||
V(Switch, (GateRef gate, GateRef input, const std::vector<GateRef> &outList)) \
|
||||
V(SwitchCase, (GateRef gate, GateRef switchBranch, GateRef out)) \
|
||||
V(Phi, (GateRef gate, const std::vector<GateRef> &srcGates)) \
|
||||
V(Return, (GateRef gate, GateRef popCount, const std::vector<GateRef> &operands) const) \
|
||||
V(ReturnVoid, (GateRef gate) const) \
|
||||
V(CastIntXToIntY, (GateRef gate, GateRef e1) const) \
|
||||
V(ChangeInt32ToDouble, (GateRef gate, GateRef e1) const) \
|
||||
V(ChangeDoubleToInt32, (GateRef gate, GateRef e1) const) \
|
||||
V(CastInt64ToDouble, (GateRef gate, GateRef e1) const) \
|
||||
V(CastDoubleToInt, (GateRef gate, GateRef e1) const) \
|
||||
V(CastInt64ToPointer, (GateRef gate, GateRef e1) const) \
|
||||
V(IntLsl, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(IntMod, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(FloatMod, (GateRef gate, GateRef e1, GateRef e2) const) \
|
||||
V(ChangeTaggedPointerToInt64, (GateRef gate, GateRef e1) const)
|
||||
|
||||
class LLVMIRBuilder {
|
||||
public:
|
||||
explicit LLVMIRBuilder(const std::vector<std::vector<AddrShift>> *schedule, const Circuit *circuit,
|
||||
LLVMStubModule *module, LLVMValueRef function);
|
||||
explicit LLVMIRBuilder(const std::vector<std::vector<GateRef>> *schedule, const Circuit *circuit,
|
||||
LLVMStubModule *module, LLVMValueRef function,
|
||||
const char *hostTriple = TripleConst::GetLLVMAmd64Triple());
|
||||
~LLVMIRBuilder();
|
||||
void Build();
|
||||
|
||||
@@ -201,28 +218,47 @@ private:
|
||||
#define DECLAREVISITOPCODE(name, signature) void Visit##name signature;
|
||||
OPCODES(DECLAREVISITOPCODE)
|
||||
#undef DECLAREVISITOPCODE
|
||||
#define DECLAREHANDLEOPCODE(name, ignore) void Handle##name(AddrShift gate);
|
||||
#define DECLAREHANDLEOPCODE(name, ignore) void Handle##name(GateRef gate);
|
||||
OPCODES(DECLAREHANDLEOPCODE)
|
||||
#undef DECLAREHANDLEOPCODE
|
||||
|
||||
BasicBlock *EnsurBasicBlock(int id);
|
||||
LLVMValueRef LLVMCallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder);
|
||||
LLVMValueRef LLVMCallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder, bool isCaller);
|
||||
void SaveCallerSp();
|
||||
LLVMValueRef LLVMCallerSp(LLVMModuleRef &module, LLVMBuilderRef &builder,
|
||||
LLVMMetadataRef meta);
|
||||
void PrologueHandle(LLVMModuleRef &module, LLVMBuilderRef &builder);
|
||||
LLVMBasicBlockRef EnsureLLVMBB(BasicBlock *bb) const;
|
||||
LLVMTFBuilderBasicBlockImpl *EnsureLLVMBBImpl(BasicBlock *bb) const;
|
||||
void StartLLVMBuilder(BasicBlock *bb) const;
|
||||
|
||||
LLVMTypeRef GetMachineRepType(MachineRep rep) const;
|
||||
int FindBasicBlock(AddrShift gate) const;
|
||||
int FindBasicBlock(GateRef gate) const;
|
||||
void EndCurrentBlock() const;
|
||||
void End();
|
||||
|
||||
void ProcessPhiWorkList();
|
||||
void AssignHandleMap();
|
||||
std::string LLVMValueToString(LLVMValueRef val) const;
|
||||
LLVMTypeRef ConvertLLVMTypeFromTypeCode(TypeCode type) const;
|
||||
|
||||
LLVMTypeRef GetArchRelate() const
|
||||
{
|
||||
if (triple_ == TripleConst::GetLLVMArm32Triple()) {
|
||||
return LLVMInt32Type();
|
||||
}
|
||||
return LLVMInt64Type();
|
||||
}
|
||||
LLVMTypeRef ConvertLLVMTypeFromGate(GateRef gate) const;
|
||||
LLVMValueRef PointerAdd(LLVMValueRef baseAddr, LLVMValueRef offset, LLVMTypeRef rep) const;
|
||||
LLVMValueRef VectorAdd(LLVMValueRef e1Value, LLVMValueRef e2Value, LLVMTypeRef rep) const;
|
||||
LLVMValueRef CanonicalizeToInt(LLVMValueRef value) const;
|
||||
|
||||
LLVMValueRef CanonicalizeToPtr(LLVMValueRef value) const;
|
||||
|
||||
private:
|
||||
const std::vector<std::vector<AddrShift>> *schedule_ {nullptr};
|
||||
|
||||
const std::vector<std::vector<GateRef>> *schedule_ {nullptr};
|
||||
const Circuit *circuit_ {nullptr};
|
||||
BasicBlock *currentBb_ {nullptr};
|
||||
int lineNumber_ {0};
|
||||
@@ -238,6 +274,7 @@ private:
|
||||
LLVMStubModule *stubModule_ {nullptr};
|
||||
std::unordered_map<OpCode::Op, HandleType> opCodeHandleMap_;
|
||||
std::set<OpCode::Op> opCodeHandleIgnore;
|
||||
const char *triple_;
|
||||
};
|
||||
} // namespace kungfu
|
||||
#endif // PANDA_RUNTIME_ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
|
||||
#endif // PANDA_RUNTIME_ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H
|
||||
|
||||
@@ -18,21 +18,21 @@
|
||||
|
||||
namespace kungfu {
|
||||
enum class MachineType {
|
||||
NONE_TYPE,
|
||||
BOOL_TYPE,
|
||||
INT8_TYPE,
|
||||
INT16_TYPE,
|
||||
INT32_TYPE,
|
||||
INT64_TYPE,
|
||||
UINT8_TYPE,
|
||||
UINT16_TYPE,
|
||||
UINT32_TYPE,
|
||||
UINT64_TYPE,
|
||||
POINTER_TYPE,
|
||||
TAGGED_TYPE,
|
||||
TAGGED_POINTER_TYPE,
|
||||
FLOAT32_TYPE,
|
||||
FLOAT64_TYPE,
|
||||
NONE,
|
||||
BOOL,
|
||||
INT8,
|
||||
INT16,
|
||||
INT32,
|
||||
INT64,
|
||||
UINT8,
|
||||
UINT16,
|
||||
UINT32,
|
||||
UINT64,
|
||||
FLOAT32,
|
||||
FLOAT64,
|
||||
NATIVE_POINTER, // GC will not visit NATIVE_POINTER.
|
||||
TAGGED, // GC cares
|
||||
TAGGED_POINTER,
|
||||
};
|
||||
} // namespace kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_MACHINE_TYPE_H
|
||||
@@ -20,17 +20,17 @@
|
||||
#include "ecmascript/compiler/verifier.h"
|
||||
|
||||
namespace kungfu {
|
||||
using DominatorTreeInfo = std::tuple<std::vector<AddrShift>, std::unordered_map<AddrShift, size_t>,
|
||||
using DominatorTreeInfo = std::tuple<std::vector<GateRef>, std::unordered_map<GateRef, size_t>,
|
||||
std::vector<size_t>>;
|
||||
DominatorTreeInfo Scheduler::CalculateDominatorTree(const Circuit *circuit)
|
||||
{
|
||||
std::vector<AddrShift> bbGatesList;
|
||||
std::unordered_map<AddrShift, size_t> bbGatesAddrToIdx;
|
||||
std::unordered_map<AddrShift, size_t> dfsTimestamp;
|
||||
std::vector<GateRef> bbGatesList;
|
||||
std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
|
||||
std::unordered_map<GateRef, size_t> dfsTimestamp;
|
||||
circuit->AdvanceTime();
|
||||
{
|
||||
size_t timestamp = 0;
|
||||
std::deque<AddrShift> pendingList;
|
||||
std::deque<GateRef> pendingList;
|
||||
auto startGate = Circuit::GetCircuitRoot(OpCode(OpCode::STATE_ENTRY));
|
||||
circuit->SetMark(startGate, MarkCode::VISITED);
|
||||
pendingList.push_back(startGate);
|
||||
@@ -101,18 +101,18 @@ DominatorTreeInfo Scheduler::CalculateDominatorTree(const Circuit *circuit)
|
||||
return {bbGatesList, bbGatesAddrToIdx, immDom};
|
||||
}
|
||||
|
||||
std::vector<std::vector<AddrShift>> Scheduler::Run(const Circuit *circuit)
|
||||
std::vector<std::vector<GateRef>> Scheduler::Run(const Circuit *circuit)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (!Verifier::Run(circuit)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
std::vector<AddrShift> bbGatesList;
|
||||
std::unordered_map<AddrShift, size_t> bbGatesAddrToIdx;
|
||||
std::vector<GateRef> bbGatesList;
|
||||
std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
|
||||
std::vector<size_t> immDom;
|
||||
std::tie(bbGatesList, bbGatesAddrToIdx, immDom) = Scheduler::CalculateDominatorTree(circuit);
|
||||
std::vector<std::vector<AddrShift>> result(bbGatesList.size());
|
||||
std::vector<std::vector<GateRef>> result(bbGatesList.size());
|
||||
for (size_t idx = 0; idx < bbGatesList.size(); idx++) {
|
||||
result[idx].push_back(bbGatesList[idx]);
|
||||
}
|
||||
@@ -162,14 +162,14 @@ std::vector<std::vector<AddrShift>> Scheduler::Run(const Circuit *circuit)
|
||||
return jumpUp[nodeA][0];
|
||||
};
|
||||
{
|
||||
std::vector<AddrShift> order;
|
||||
std::vector<GateRef> order;
|
||||
auto lowerBound =
|
||||
Scheduler::CalculateSchedulingLowerBound(circuit, bbGatesAddrToIdx, lowestCommonAncestor, &order).value();
|
||||
for (const auto &schedulableGate : order) {
|
||||
result[lowerBound.at(schedulableGate)].push_back(schedulableGate);
|
||||
}
|
||||
auto argList = circuit->GetOutVector(Circuit::GetCircuitRoot(OpCode(OpCode::ARG_LIST)));
|
||||
std::sort(argList.begin(), argList.end(), [&](const AddrShift &lhs, const AddrShift &rhs) -> bool {
|
||||
std::sort(argList.begin(), argList.end(), [&](const GateRef &lhs, const GateRef &rhs) -> bool {
|
||||
return circuit->GetBitField(lhs) > circuit->GetBitField(rhs);
|
||||
});
|
||||
for (const auto &arg : argList) {
|
||||
@@ -186,12 +186,12 @@ std::vector<std::vector<AddrShift>> Scheduler::Run(const Circuit *circuit)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<std::unordered_map<AddrShift, size_t>> Scheduler::CalculateSchedulingUpperBound(const Circuit *circuit,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor, const std::vector<AddrShift> &schedulableGatesList)
|
||||
std::optional<std::unordered_map<GateRef, size_t>> Scheduler::CalculateSchedulingUpperBound(const Circuit *circuit,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor, const std::vector<GateRef> &schedulableGatesList)
|
||||
{
|
||||
std::unordered_map<AddrShift, size_t> upperBound;
|
||||
std::function<std::optional<size_t>(AddrShift)> dfs = [&](AddrShift curGate) -> std::optional<size_t> {
|
||||
std::unordered_map<GateRef, size_t> upperBound;
|
||||
std::function<std::optional<size_t>(GateRef)> dfs = [&](GateRef curGate) -> std::optional<size_t> {
|
||||
if (upperBound.count(curGate) > 0) {
|
||||
return upperBound[curGate];
|
||||
}
|
||||
@@ -230,14 +230,14 @@ std::optional<std::unordered_map<AddrShift, size_t>> Scheduler::CalculateSchedul
|
||||
return upperBound;
|
||||
}
|
||||
|
||||
std::optional<std::unordered_map<AddrShift, size_t>> Scheduler::CalculateSchedulingLowerBound(const Circuit *circuit,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor, std::vector<AddrShift> *order)
|
||||
std::optional<std::unordered_map<GateRef, size_t>> Scheduler::CalculateSchedulingLowerBound(const Circuit *circuit,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor, std::vector<GateRef> *order)
|
||||
{
|
||||
std::unordered_map<AddrShift, size_t> lowerBound;
|
||||
std::unordered_map<AddrShift, size_t> useCount;
|
||||
std::deque<AddrShift> pendingList;
|
||||
std::vector<AddrShift> bbAndFixedGatesList;
|
||||
std::unordered_map<GateRef, size_t> lowerBound;
|
||||
std::unordered_map<GateRef, size_t> useCount;
|
||||
std::deque<GateRef> pendingList;
|
||||
std::vector<GateRef> bbAndFixedGatesList;
|
||||
for (const auto &item : bbGatesAddrToIdx) {
|
||||
bbAndFixedGatesList.push_back(item.first);
|
||||
for (const auto &succGate : circuit->GetOutVector(item.first)) {
|
||||
@@ -246,7 +246,7 @@ std::optional<std::unordered_map<AddrShift, size_t>> Scheduler::CalculateSchedul
|
||||
}
|
||||
}
|
||||
}
|
||||
std::function<void(AddrShift)> dfsVisit = [&](AddrShift curGate) {
|
||||
std::function<void(GateRef)> dfsVisit = [&](GateRef curGate) {
|
||||
for (const auto &prevGate : circuit->GetInVector(curGate)) {
|
||||
if (circuit->GetOpCode(prevGate).IsSchedulable()) {
|
||||
useCount[prevGate]++;
|
||||
@@ -259,7 +259,7 @@ std::optional<std::unordered_map<AddrShift, size_t>> Scheduler::CalculateSchedul
|
||||
for (const auto &gate : bbAndFixedGatesList) {
|
||||
dfsVisit(gate);
|
||||
}
|
||||
std::function<void(AddrShift)> dfsFinish = [&](AddrShift curGate) {
|
||||
std::function<void(GateRef)> dfsFinish = [&](GateRef curGate) {
|
||||
size_t cnt = 0;
|
||||
for (const auto &prevGate : circuit->GetInVector(curGate)) {
|
||||
if (circuit->GetOpCode(prevGate).IsSchedulable()) {
|
||||
@@ -294,10 +294,10 @@ std::optional<std::unordered_map<AddrShift, size_t>> Scheduler::CalculateSchedul
|
||||
return lowerBound;
|
||||
}
|
||||
|
||||
void Scheduler::Print(const std::vector<std::vector<AddrShift>> *cfg, const Circuit *circuit)
|
||||
void Scheduler::Print(const std::vector<std::vector<GateRef>> *cfg, const Circuit *circuit)
|
||||
{
|
||||
std::vector<AddrShift> bbGatesList;
|
||||
std::unordered_map<AddrShift, size_t> bbGatesAddrToIdx;
|
||||
std::vector<GateRef> bbGatesList;
|
||||
std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
|
||||
std::vector<size_t> immDom;
|
||||
std::tie(bbGatesList, bbGatesAddrToIdx, immDom) = Scheduler::CalculateDominatorTree(circuit);
|
||||
std::cout << "==========================================================================" << std::endl;
|
||||
|
||||
@@ -25,18 +25,18 @@
|
||||
#include "ecmascript/compiler/circuit.h"
|
||||
|
||||
namespace kungfu {
|
||||
using ControlFlowGraph = std::vector<std::vector<AddrShift>>;
|
||||
using ControlFlowGraph = std::vector<std::vector<GateRef>>;
|
||||
class Scheduler {
|
||||
public:
|
||||
static std::tuple<std::vector<AddrShift>, std::unordered_map<AddrShift, size_t>, std::vector<size_t>>
|
||||
static std::tuple<std::vector<GateRef>, std::unordered_map<GateRef, size_t>, std::vector<size_t>>
|
||||
CalculateDominatorTree(const Circuit *circuit);
|
||||
static ControlFlowGraph Run(const Circuit *circuit);
|
||||
static std::optional<std::unordered_map<AddrShift, size_t>> CalculateSchedulingUpperBound(const Circuit *circuit,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor, const std::vector<AddrShift> &schedulableGatesList);
|
||||
static std::optional<std::unordered_map<AddrShift, size_t>> CalculateSchedulingLowerBound(const Circuit *circuit,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor, std::vector<AddrShift> *order = nullptr);
|
||||
static std::optional<std::unordered_map<GateRef, size_t>> CalculateSchedulingUpperBound(const Circuit *circuit,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor, const std::vector<GateRef> &schedulableGatesList);
|
||||
static std::optional<std::unordered_map<GateRef, size_t>> CalculateSchedulingLowerBound(const Circuit *circuit,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor, std::vector<GateRef> *order = nullptr);
|
||||
static void Print(const ControlFlowGraph *cfg, const Circuit *circuit);
|
||||
};
|
||||
}; // namespace kungfu
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2128
-214
File diff suppressed because it is too large
Load Diff
+370
-1288
File diff suppressed because it is too large
Load Diff
@@ -1,205 +1,239 @@
|
||||
/*
|
||||
* 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 "stub_aot_compiler.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include "fast_stub.h"
|
||||
#include "generated/stub_aot_options_gen.h"
|
||||
#include "libpandabase/utils/pandargs.h"
|
||||
#include "libpandabase/utils/span.h"
|
||||
#include "llvm_codegen.h"
|
||||
#include "scheduler.h"
|
||||
#include "stub.h"
|
||||
#include "verifier.h"
|
||||
|
||||
namespace kungfu {
|
||||
class PassPayLoad {
|
||||
public:
|
||||
explicit PassPayLoad(Circuit *circuit, LLVMStubModule *module) : circuit_(circuit), module_(module) {}
|
||||
~PassPayLoad() = default;
|
||||
const ControlFlowGraph &GetScheduleResult() const
|
||||
{
|
||||
return cfg_;
|
||||
}
|
||||
|
||||
void SetScheduleResult(const ControlFlowGraph &result)
|
||||
{
|
||||
cfg_ = result;
|
||||
}
|
||||
|
||||
Circuit *GetCircuit() const
|
||||
{
|
||||
return circuit_;
|
||||
}
|
||||
|
||||
LLVMStubModule *GetStubModule() const
|
||||
{
|
||||
return module_;
|
||||
}
|
||||
|
||||
private:
|
||||
Circuit *circuit_;
|
||||
LLVMStubModule *module_;
|
||||
ControlFlowGraph cfg_;
|
||||
};
|
||||
|
||||
class PassRunner {
|
||||
public:
|
||||
explicit PassRunner(PassPayLoad *data) : data_(data) {}
|
||||
~PassRunner() = default;
|
||||
template <typename T, typename... Args>
|
||||
bool RunPass(Args... args)
|
||||
{
|
||||
T pass;
|
||||
return pass.Run(data_, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
PassPayLoad *data_;
|
||||
};
|
||||
|
||||
class VerifierPass {
|
||||
public:
|
||||
bool Run(PassPayLoad *data)
|
||||
{
|
||||
Verifier::Run(data->GetCircuit());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class SchedulerPass {
|
||||
public:
|
||||
bool Run(PassPayLoad *data)
|
||||
{
|
||||
data->SetScheduleResult(Scheduler::Run(data->GetCircuit()));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class LLVMCodegenPass {
|
||||
public:
|
||||
bool Run(PassPayLoad *data, int index)
|
||||
{
|
||||
auto stubModule = data->GetStubModule();
|
||||
LLVMCodeGeneratorImpl llvmImpl(stubModule);
|
||||
CodeGenerator codegen(&llvmImpl);
|
||||
codegen.Run(data->GetCircuit(), data->GetScheduleResult(), index);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void StubAotCompiler::BuildStubModuleAndSave(const char *triple, panda::ecmascript::StubModule *module,
|
||||
const std::string &filename)
|
||||
{
|
||||
LLVMStubModule stubModule("fast_stubs", triple);
|
||||
stubModule.Initialize();
|
||||
for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) {
|
||||
auto stub = stubs_[i];
|
||||
if (stub != nullptr) {
|
||||
std::cout << "Stub Name: " << stub->GetMethodName() << std::endl;
|
||||
stub->GenerateCircuit();
|
||||
auto circuit = stub->GetEnvironment()->GetCircuit();
|
||||
PassPayLoad data(circuit, &stubModule);
|
||||
PassRunner pipeline(&data);
|
||||
pipeline.RunPass<VerifierPass>();
|
||||
pipeline.RunPass<SchedulerPass>();
|
||||
pipeline.RunPass<LLVMCodegenPass>(i);
|
||||
}
|
||||
}
|
||||
|
||||
LLVMModuleAssembler assembler(&stubModule, triple);
|
||||
assembler.AssembleModule();
|
||||
assembler.AssembleStubModule(module);
|
||||
|
||||
auto codeSize = assembler.GetCodeSize();
|
||||
panda::ecmascript::MachineCode *code = reinterpret_cast<panda::ecmascript::MachineCode *>(
|
||||
new uint64_t[(panda::ecmascript::MachineCode::SIZE + codeSize) / sizeof(uint64_t) + 1]);
|
||||
code->SetInstructionSizeInBytes(nullptr, panda::ecmascript::JSTaggedValue(codeSize),
|
||||
panda::ecmascript::SKIP_BARRIER);
|
||||
|
||||
assembler.CopyAssemblerToCode(code);
|
||||
|
||||
module->SetCode(code);
|
||||
module->Save(filename);
|
||||
|
||||
delete code;
|
||||
}
|
||||
} // namespace kungfu
|
||||
|
||||
#define SET_STUB_TO_MODULE(module, name) \
|
||||
kungfu::Circuit name##Circuit; \
|
||||
kungfu::name##Stub name##Stub(& name##Circuit); \
|
||||
module.SetStub(FAST_STUB_ID(name), & name##Stub);
|
||||
#define SET_ALL_STUB_TO_MODEULE(module) \
|
||||
SET_STUB_TO_MODULE(module, FastAdd) \
|
||||
SET_STUB_TO_MODULE(module, FastSub) \
|
||||
SET_STUB_TO_MODULE(module, FastMul) \
|
||||
SET_STUB_TO_MODULE(module, FastDiv) \
|
||||
SET_STUB_TO_MODULE(module, FastMod) \
|
||||
SET_STUB_TO_MODULE(module, FastTypeOf) \
|
||||
SET_STUB_TO_MODULE(module, FastEqual) \
|
||||
SET_STUB_TO_MODULE(module, FindOwnElement) \
|
||||
SET_STUB_TO_MODULE(module, GetElement) \
|
||||
SET_STUB_TO_MODULE(module, FindOwnElement2) \
|
||||
SET_STUB_TO_MODULE(module, SetElement) \
|
||||
SET_STUB_TO_MODULE(module, GetPropertyByIndex) \
|
||||
SET_STUB_TO_MODULE(module, SetPropertyByIndex) \
|
||||
SET_STUB_TO_MODULE(module, FunctionCallInternal) \
|
||||
SET_STUB_TO_MODULE(module, GetPropertyByName) \
|
||||
SET_STUB_TO_MODULE(module, GetPropertyByValue)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define SET_TEST_STUB_TO_MODEULE(module) \
|
||||
SET_STUB_TO_MODULE(module, FastMulGCTest)
|
||||
#endif
|
||||
|
||||
int main(const int argc, const char **argv)
|
||||
{
|
||||
panda::Span<const char *> sp(argv, argc);
|
||||
panda::Stub_Aot_Options stubOptions(sp[0]);
|
||||
panda::PandArg<bool> help("help", false, "Print this message and exit");
|
||||
panda::PandArg<bool> options("options", false, "Print compiler options");
|
||||
panda::PandArgParser paParser;
|
||||
|
||||
stubOptions.AddOptions(&paParser);
|
||||
paParser.Add(&help);
|
||||
paParser.Add(&options);
|
||||
|
||||
if (!paParser.Parse(argc, argv) || help.GetValue()) {
|
||||
std::cerr << paParser.GetErrorString() << std::endl;
|
||||
std::cerr << "Usage: " << "ark_stub_opt" << " [OPTIONS]" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "optional arguments:" << std::endl;
|
||||
std::cerr << paParser.GetHelpString() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string moduleFilename = stubOptions.GetStubOutputFile();
|
||||
std::string tripes = stubOptions.GetTargetTriple();
|
||||
|
||||
kungfu::StubAotCompiler mouldeBuilder;
|
||||
SET_ALL_STUB_TO_MODEULE(mouldeBuilder);
|
||||
#ifndef NDEBUG
|
||||
SET_TEST_STUB_TO_MODEULE(mouldeBuilder);
|
||||
#endif
|
||||
panda::ecmascript::StubModule stubModule;
|
||||
mouldeBuilder.BuildStubModuleAndSave(tripes.c_str(), &stubModule, moduleFilename);
|
||||
|
||||
std::cout << "BuildStubModuleAndSave success" << std::endl;
|
||||
return 0;
|
||||
/*
|
||||
* 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 "stub_aot_compiler.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fast_stub.h"
|
||||
#include "generated/stub_aot_options_gen.h"
|
||||
#include "js_thread_offset_table.h"
|
||||
#include "libpandabase/utils/pandargs.h"
|
||||
#include "libpandabase/utils/span.h"
|
||||
#include "llvm_codegen.h"
|
||||
#include "scheduler.h"
|
||||
#include "stub-inl.h"
|
||||
#include "triple.h"
|
||||
#include "verifier.h"
|
||||
|
||||
namespace kungfu {
|
||||
class PassPayLoad {
|
||||
public:
|
||||
explicit PassPayLoad(Circuit *circuit, LLVMStubModule *module) : circuit_(circuit), module_(module) {}
|
||||
~PassPayLoad() = default;
|
||||
const ControlFlowGraph &GetScheduleResult() const
|
||||
{
|
||||
return cfg_;
|
||||
}
|
||||
|
||||
void SetScheduleResult(const ControlFlowGraph &result)
|
||||
{
|
||||
cfg_ = result;
|
||||
}
|
||||
|
||||
Circuit *GetCircuit() const
|
||||
{
|
||||
return circuit_;
|
||||
}
|
||||
|
||||
LLVMStubModule *GetStubModule() const
|
||||
{
|
||||
return module_;
|
||||
}
|
||||
|
||||
private:
|
||||
Circuit *circuit_;
|
||||
LLVMStubModule *module_;
|
||||
ControlFlowGraph cfg_;
|
||||
};
|
||||
|
||||
class PassRunner {
|
||||
public:
|
||||
explicit PassRunner(PassPayLoad *data) : data_(data) {}
|
||||
~PassRunner() = default;
|
||||
template<typename T, typename... Args>
|
||||
bool RunPass(Args... args)
|
||||
{
|
||||
T pass;
|
||||
return pass.Run(data_, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
PassPayLoad *data_;
|
||||
};
|
||||
|
||||
class VerifierPass {
|
||||
public:
|
||||
bool Run(PassPayLoad *data)
|
||||
{
|
||||
Verifier::Run(data->GetCircuit());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class SchedulerPass {
|
||||
public:
|
||||
bool Run(PassPayLoad *data)
|
||||
{
|
||||
data->SetScheduleResult(Scheduler::Run(data->GetCircuit()));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class LLVMCodegenPass {
|
||||
public:
|
||||
void CreateCodeGen(const char *targetTriple, LLVMStubModule *module)
|
||||
{
|
||||
if (targetTriple == TripleConst::GetLLVMArm64Triple()) {
|
||||
llvmImpl_ = std::make_unique<LLVMAarch64CodeGeneratorImpl>(module);
|
||||
} else if (targetTriple == TripleConst::GetLLVMArm32Triple()) {
|
||||
llvmImpl_ = std::make_unique<LLVMArm32CodeGeneratorImpl>(module);
|
||||
} else {
|
||||
llvmImpl_ = std::make_unique<LLVMCodeGeneratorImpl>(module);
|
||||
}
|
||||
}
|
||||
bool Run(PassPayLoad *data, int index, const char* triple)
|
||||
{
|
||||
auto stubModule = data->GetStubModule();
|
||||
CreateCodeGen(stubModule->GetTargetTriple(), stubModule);
|
||||
CodeGenerator codegen(llvmImpl_, triple);
|
||||
codegen.Run(data->GetCircuit(), data->GetScheduleResult(), index);
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<CodeGeneratorImpl> llvmImpl_{nullptr};
|
||||
};
|
||||
|
||||
void StubAotCompiler::BuildStubModuleAndSave(const char *triple, panda::ecmascript::StubModule *module,
|
||||
const std::string &filename)
|
||||
{
|
||||
LLVMStubModule stubModule("fast_stubs", triple);
|
||||
stubModule.Initialize();
|
||||
for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) {
|
||||
auto stub = stubs_[i];
|
||||
if (stub != nullptr) {
|
||||
std::cout << "Stub Name: " << stub->GetMethodName() << std::endl;
|
||||
stub->GenerateCircuit();
|
||||
auto circuit = stub->GetEnvironment()->GetCircuit();
|
||||
PassPayLoad data(circuit, &stubModule);
|
||||
PassRunner pipeline(&data);
|
||||
pipeline.RunPass<VerifierPass>();
|
||||
pipeline.RunPass<SchedulerPass>();
|
||||
pipeline.RunPass<LLVMCodegenPass>(i, triple);
|
||||
}
|
||||
}
|
||||
|
||||
LLVMModuleAssembler assembler(&stubModule, triple);
|
||||
assembler.AssembleModule();
|
||||
assembler.AssembleStubModule(module);
|
||||
|
||||
auto codeSize = assembler.GetCodeSize();
|
||||
panda::ecmascript::MachineCode *code = reinterpret_cast<panda::ecmascript::MachineCode *>(
|
||||
new uint64_t[(panda::ecmascript::MachineCode::SIZE + codeSize) / sizeof(uint64_t) + 1]);
|
||||
code->SetInstructionSizeInBytes(nullptr, panda::ecmascript::JSTaggedValue(codeSize),
|
||||
panda::ecmascript::SKIP_BARRIER);
|
||||
|
||||
assembler.CopyAssemblerToCode(code);
|
||||
|
||||
module->SetCode(code);
|
||||
module->Save(filename);
|
||||
|
||||
delete[] code;
|
||||
}
|
||||
} // namespace kungfu
|
||||
|
||||
#define SET_STUB_TO_MODULE(module, name, triple) \
|
||||
kungfu::Circuit name##Circuit; \
|
||||
kungfu::name##Stub name##Stub(& name##Circuit, triple); \
|
||||
module.SetStub(FAST_STUB_ID(name), &name##Stub);
|
||||
#ifdef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
#define SET_ALL_STUB_TO_MODEULE(module, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastAdd, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastSub, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastMul, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastDiv, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastMod, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastTypeOf, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastEqual, triple) \
|
||||
SET_STUB_TO_MODULE(module, FindOwnElement2, triple) \
|
||||
SET_STUB_TO_MODULE(module, GetPropertyByIndex, triple) \
|
||||
SET_STUB_TO_MODULE(module, SetPropertyByIndex, triple) \
|
||||
SET_STUB_TO_MODULE(module, GetPropertyByName, triple) \
|
||||
SET_STUB_TO_MODULE(module, GetPropertyByValue, triple) \
|
||||
SET_STUB_TO_MODULE(module, SetPropertyByName, triple) \
|
||||
SET_STUB_TO_MODULE(module, SetPropertyByNameWithOwn, triple) \
|
||||
SET_STUB_TO_MODULE(module, TryLoadICByName, triple) \
|
||||
SET_STUB_TO_MODULE(module, TryLoadICByValue, triple) \
|
||||
SET_STUB_TO_MODULE(module, TryStoreICByName, triple) \
|
||||
SET_STUB_TO_MODULE(module, TryStoreICByValue, triple)
|
||||
#else
|
||||
#define SET_ALL_STUB_TO_MODEULE(module, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastAdd, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastSub, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastMul, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastDiv, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastMod, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastTypeOf, triple) \
|
||||
SET_STUB_TO_MODULE(module, FastEqual, triple)
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define SET_TEST_STUB_TO_MODEULE(module, hostTriple) \
|
||||
SET_STUB_TO_MODULE(module, FastMulGCTest, hostTriple)
|
||||
#endif
|
||||
|
||||
int main(const int argc, const char **argv)
|
||||
{
|
||||
panda::Span<const char *> sp(argv, argc);
|
||||
panda::Stub_Aot_Options stubOptions(sp[0]);
|
||||
panda::PandArg<bool> help("help", false, "Print this message and exit");
|
||||
panda::PandArg<bool> options("options", false, "Print compiler options");
|
||||
panda::PandArgParser paParser;
|
||||
|
||||
stubOptions.AddOptions(&paParser);
|
||||
paParser.Add(&help);
|
||||
paParser.Add(&options);
|
||||
|
||||
if (!paParser.Parse(argc, argv) || help.GetValue()) {
|
||||
std::cerr << paParser.GetErrorString() << std::endl;
|
||||
std::cerr << "Usage: " << "ark_stub_opt" << " [OPTIONS]" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "optional arguments:" << std::endl;
|
||||
|
||||
std::cerr << paParser.GetHelpString() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string tripleString = stubOptions.GetTargetTriple();
|
||||
const char *triple = kungfu::TripleConst::StringTripleToConst(tripleString);
|
||||
std::string moduleFilename = stubOptions.GetStubOutputFile();
|
||||
|
||||
kungfu::OffsetTable::CreateInstance(triple);
|
||||
kungfu::StubAotCompiler mouldeBuilder;
|
||||
SET_ALL_STUB_TO_MODEULE(mouldeBuilder, triple);
|
||||
#ifndef NDEBUG
|
||||
SET_TEST_STUB_TO_MODEULE(mouldeBuilder, triple);
|
||||
#endif
|
||||
|
||||
panda::ecmascript::StubModule stubModule;
|
||||
mouldeBuilder.BuildStubModuleAndSave(triple, &stubModule, moduleFilename);
|
||||
kungfu::OffsetTable::Destroy();
|
||||
|
||||
std::cout << "BuildStubModuleAndSave success" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
#include "ecmascript/compiler/fast_stub_define.h"
|
||||
#include "ecmascript/compiler/machine_type.h"
|
||||
#include "libpandabase/macros.h"
|
||||
#include "libpandabase/utils/bit_field.h"
|
||||
#include "llvm-c/Types.h"
|
||||
|
||||
namespace kungfu {
|
||||
@@ -30,6 +31,7 @@ enum class ArgumentsOrder {
|
||||
|
||||
class StubDescriptor {
|
||||
public:
|
||||
using VariableArgsBits = panda::BitField<bool, 0, 1>; // 1 variable argument
|
||||
enum class CallStubKind {
|
||||
CODE_STUB,
|
||||
RUNTIME_STUB,
|
||||
@@ -114,6 +116,22 @@ public:
|
||||
return flags_;
|
||||
}
|
||||
|
||||
void SetFlags(int flag)
|
||||
{
|
||||
flags_ = flag;
|
||||
}
|
||||
|
||||
bool GetVariableArgs() const
|
||||
{
|
||||
return VariableArgsBits::Decode(flags_);
|
||||
}
|
||||
|
||||
void SetVariableArgs(bool variable)
|
||||
{
|
||||
uint64_t newVal = VariableArgsBits::Update(flags_, variable);
|
||||
SetFlags(newVal);
|
||||
}
|
||||
|
||||
CallStubKind GetStubKind() const
|
||||
{
|
||||
return kind_;
|
||||
@@ -136,7 +154,7 @@ private:
|
||||
int paramCounter_ {0};
|
||||
ArgumentsOrder order_ {ArgumentsOrder::DEFAULT_ORDER};
|
||||
|
||||
MachineType returnType_ {MachineType::NONE_TYPE};
|
||||
MachineType returnType_ {MachineType::NONE};
|
||||
std::unique_ptr<std::vector<MachineType>> paramsType_ {nullptr};
|
||||
};
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ host_unittest_action("StubTest") {
|
||||
|
||||
deps = [
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer_test(${host_toolchain})",
|
||||
"//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer_test",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,21 +18,21 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "ecmascript/builtins/builtins_promise_handler.h"
|
||||
#include "ecmascript/compiler/compiler_macros.h"
|
||||
#include "ecmascript/compiler/fast_stub.h"
|
||||
#include "ecmascript/compiler/js_thread_offset_table.h"
|
||||
#include "ecmascript/compiler/llvm_codegen.h"
|
||||
#include "ecmascript/compiler/llvm_ir_builder.h"
|
||||
#include "ecmascript/compiler/llvm/llvm_stackmap_parser.h"
|
||||
#include "ecmascript/compiler/scheduler.h"
|
||||
#include "ecmascript/compiler/stub_descriptor.h"
|
||||
#include "ecmascript/compiler/triple.h"
|
||||
#include "ecmascript/compiler/verifier.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/interpreter/fast_runtime_stub-inl.h"
|
||||
#include "ecmascript/js_array.h"
|
||||
#include "ecmascript/message_string.h"
|
||||
#include "ecmascript/tests/test_helper.h"
|
||||
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/IRReader/IRReader.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IRReader/IRReader.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
@@ -50,15 +50,18 @@ public:
|
||||
{
|
||||
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
|
||||
stubModule.Initialize();
|
||||
OffsetTable::CreateInstance(TripleConst::GetLLVMAmd64Triple());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TestHelper::DestroyEcmaVMWithScope(instance, scope);
|
||||
OffsetTable::Destroy();
|
||||
}
|
||||
|
||||
void PrintCircuitByBasicBlock(const std::vector<std::vector<AddrShift>> &cfg, const Circuit &netOfGates)
|
||||
void PrintCircuitByBasicBlock(const std::vector<std::vector<GateRef>> &cfg, const Circuit &netOfGates) const
|
||||
{
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) {
|
||||
std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":"
|
||||
<< std::endl;
|
||||
@@ -66,57 +69,26 @@ public:
|
||||
netOfGates.Print(cfg[bbIdx][instIdx - 1]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PandaVM *instance {nullptr};
|
||||
EcmaHandleScope *scope {nullptr};
|
||||
JSThread *thread {nullptr};
|
||||
LLVMStubModule stubModule {"fast_stub", "x86_64-unknown-linux-gnu"};
|
||||
LLVMStubModule stubModule {"fast_stub", TripleConst::GetLLVMAmd64Triple()};
|
||||
};
|
||||
|
||||
|
||||
HWTEST_F_L0(StubTest, FastLoadElement)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetTestFunction(FAST_STUB_ID(FastLoadElement));
|
||||
Circuit netOfGates;
|
||||
FastArrayLoadElementStub optimizer(&netOfGates);
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
bool result = Verifier::Run(&netOfGates);
|
||||
ASSERT_TRUE(result);
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
assembler.Run();
|
||||
// Testcase build and run
|
||||
auto fn = reinterpret_cast<uint64_t (*)(JSArray *, int)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> values(factory->NewTaggedArray(5)); // 5 : 5 elements in array
|
||||
for (int i = 0; i < 5; i++) { // 5 : 5 elements in array
|
||||
values->Set(thread, i, JSTaggedValue(i));
|
||||
}
|
||||
JSHandle<JSObject> array(JSArray::CreateArrayFromList(thread, values));
|
||||
JSArray *arr = array.GetObject<JSArray>();
|
||||
auto valValid = fn(arr, 1);
|
||||
EXPECT_EQ(valValid, 0xffff000000000001);
|
||||
auto valUndefine = fn(arr, 6); // 6 : size of array
|
||||
EXPECT_EQ(valUndefine, 0xa);
|
||||
}
|
||||
|
||||
#ifdef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
class PhiStub : public Stub {
|
||||
public:
|
||||
explicit PhiStub(Circuit *circuit) : Stub("Phi", 1, circuit) {}
|
||||
explicit PhiStub(Circuit *circuit, const char* triple) : Stub("Phi", 1, circuit, triple) {}
|
||||
~PhiStub() = default;
|
||||
NO_MOVE_SEMANTIC(PhiStub);
|
||||
NO_COPY_SEMANTIC(PhiStub);
|
||||
void GenerateCircuit() override
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
DEFVARIABLE(z, MachineType::INT32_TYPE, GetInt32Constant(0));
|
||||
DEFVARIABLE(x, MachineType::INT32_TYPE, Int32Argument(0));
|
||||
DEFVARIABLE(z, MachineType::INT32, GetInt32Constant(0));
|
||||
DEFVARIABLE(x, MachineType::INT32, Int32Argument(0));
|
||||
Label ifTrue(env);
|
||||
Label ifFalse(env);
|
||||
Label next(env);
|
||||
@@ -138,34 +110,34 @@ HWTEST_F_L0(StubTest, PhiGateTest)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetTestFunction(FAST_STUB_ID(PhiGateTest));
|
||||
Circuit netOfGates;
|
||||
PhiStub optimizer(&netOfGates);
|
||||
PhiStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
// Testcase build and run
|
||||
auto fn = reinterpret_cast<int (*)(int)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
auto valA = fn(3); // 3 : size of array
|
||||
auto valB = fn(0);
|
||||
EXPECT_EQ(valA, 103); // 103 : eXpert res for fn(3)
|
||||
EXPECT_EQ(valB, 100); // 100 : eXpert res for fn(0)
|
||||
EXPECT_EQ(valA, 103); // 103 : expected res for fn(3)
|
||||
EXPECT_EQ(valB, 100); // 100 : expected res for fn(0)
|
||||
}
|
||||
|
||||
class LoopStub : public Stub {
|
||||
public:
|
||||
explicit LoopStub(Circuit *circuit) : Stub("loop", 1, circuit) {}
|
||||
explicit LoopStub(Circuit *circuit, const char* triple) : Stub("loop", 1, circuit, triple) {}
|
||||
~LoopStub() = default;
|
||||
NO_MOVE_SEMANTIC(LoopStub);
|
||||
NO_COPY_SEMANTIC(LoopStub);
|
||||
void GenerateCircuit() override
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
DEFVARIABLE(z, MachineType::INT32_TYPE, GetInt32Constant(0));
|
||||
DEFVARIABLE(y, MachineType::INT32_TYPE, Int32Argument(0));
|
||||
DEFVARIABLE(z, MachineType::INT32, GetInt32Constant(0));
|
||||
DEFVARIABLE(y, MachineType::INT32, Int32Argument(0));
|
||||
Label loopHead(env);
|
||||
Label loopEnd(env);
|
||||
Label afterLoop(env);
|
||||
@@ -197,37 +169,37 @@ HWTEST_F_L0(StubTest, LoopTest)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetTestFunction(FAST_STUB_ID(LoopTest));
|
||||
Circuit netOfGates;
|
||||
LoopStub optimizer(&netOfGates);
|
||||
LoopStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
// Testcase build and run
|
||||
auto fn = reinterpret_cast<int (*)(int)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
auto valA = fn(1);
|
||||
auto valB = fn(9); // 9 : size of array
|
||||
auto valC = fn(11); // 11 : size of array
|
||||
EXPECT_EQ(valA, 109); // 109 : eXpert res for fn(1)
|
||||
EXPECT_EQ(valB, 19); // 10 : eXpert res for fn(9)
|
||||
EXPECT_EQ(valA, 109); // 109 : expected res for fn(1)
|
||||
EXPECT_EQ(valB, 19); // 10 : expected res for fn(9)
|
||||
EXPECT_EQ(valC, 0);
|
||||
}
|
||||
|
||||
class LoopStub1 : public Stub {
|
||||
public:
|
||||
explicit LoopStub1(Circuit *circuit) : Stub("loop1", 1, circuit) {}
|
||||
explicit LoopStub1(Circuit *circuit, const char* triple) : Stub("loop1", 1, circuit, triple) {}
|
||||
~LoopStub1() = default;
|
||||
NO_MOVE_SEMANTIC(LoopStub1);
|
||||
NO_COPY_SEMANTIC(LoopStub1);
|
||||
void GenerateCircuit() override
|
||||
{
|
||||
auto env = GetEnvironment();
|
||||
DEFVARIABLE(y, MachineType::INT32_TYPE, Int32Argument(0));
|
||||
DEFVARIABLE(x, MachineType::INT32_TYPE, Int32Argument(0));
|
||||
DEFVARIABLE(z, MachineType::INT32_TYPE, Int32Argument(0));
|
||||
DEFVARIABLE(y, MachineType::INT32, Int32Argument(0));
|
||||
DEFVARIABLE(x, MachineType::INT32, Int32Argument(0));
|
||||
DEFVARIABLE(z, MachineType::INT32, Int32Argument(0));
|
||||
Label loopHead(env);
|
||||
Label loopEnd(env);
|
||||
Label afterLoop(env);
|
||||
@@ -254,29 +226,25 @@ public:
|
||||
HWTEST_F_L0(StubTest, LoopTest1)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
LLVMTypeRef paramTys[] = {
|
||||
LLVMInt32Type(),
|
||||
};
|
||||
LLVMValueRef function = LLVMAddFunction(module, "LoopTest1", LLVMFunctionType(LLVMInt32Type(), paramTys, 1, 0));
|
||||
auto function = stubModule.GetTestFunction(FAST_STUB_ID(LoopTest1));
|
||||
Circuit netOfGates;
|
||||
LoopStub1 optimizer(&netOfGates);
|
||||
LoopStub1 optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto engine = assembler.GetEngine();
|
||||
// Testcase build and run
|
||||
auto fn = reinterpret_cast<int (*)(int)>(LLVMGetPointerToGlobal(engine, function));
|
||||
auto fn = reinterpret_cast<int (*)(int)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
auto valA = fn(1);
|
||||
auto valB = fn(9); // 9 : size of array
|
||||
auto valC = fn(11); // 11 : size of array
|
||||
EXPECT_EQ(valA, 10); // 10 : eXpert res for fn(1)
|
||||
EXPECT_EQ(valB, 10); // 10 : eXpert res for fn(9)
|
||||
EXPECT_EQ(valC, 11); // 10 : eXpert res for fn(11)
|
||||
EXPECT_EQ(valA, 10); // 10 : expected res for fn(1)
|
||||
EXPECT_EQ(valB, 10); // 10 : expected res for fn(9)
|
||||
EXPECT_EQ(valC, 11); // 10 : expected res for fn(11)
|
||||
}
|
||||
|
||||
HWTEST_F_L0(StubTest, FastAddTest)
|
||||
@@ -284,14 +252,14 @@ HWTEST_F_L0(StubTest, FastAddTest)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastAdd));
|
||||
Circuit netOfGates;
|
||||
FastAddStub optimizer(&netOfGates);
|
||||
FastAddStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
// Testcase build and run
|
||||
auto fn = reinterpret_cast<JSTaggedValue (*)(int64_t, int64_t)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
@@ -316,14 +284,14 @@ HWTEST_F_L0(StubTest, FastSubTest)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastSub));
|
||||
Circuit netOfGates;
|
||||
FastSubStub optimizer(&netOfGates);
|
||||
FastSubStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
// Testcase build and run
|
||||
auto fn = reinterpret_cast<JSTaggedValue (*)(int64_t, int64_t)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
@@ -337,20 +305,21 @@ HWTEST_F_L0(StubTest, FastSubTest)
|
||||
EXPECT_EQ(resB, JSTaggedValue(5));
|
||||
EXPECT_EQ(resC, JSTaggedValue(0));
|
||||
}
|
||||
#endif
|
||||
|
||||
HWTEST_F_L0(StubTest, FastMulTest)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastMul));
|
||||
Circuit netOfGates;
|
||||
FastMulStub optimizer(&netOfGates);
|
||||
FastMulStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
// Testcase build and run
|
||||
auto fn = reinterpret_cast<JSTaggedValue (*)(int64_t, int64_t)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
@@ -360,6 +329,10 @@ HWTEST_F_L0(StubTest, FastMulTest)
|
||||
LOG_ECMA(INFO) << "res for FastMul(-2, 1) = " << std::dec << resA.GetNumber();
|
||||
LOG_ECMA(INFO) << "res for FastMul(-7, -2) = " << std::dec << resB.GetNumber();
|
||||
LOG_ECMA(INFO) << "res for FastMul(11, 11) = " << std::dec << resC.GetNumber();
|
||||
EXPECT_EQ(resA.GetInt(), -2); // -2: test case
|
||||
EXPECT_EQ(resB.GetInt(), 14); // 14: test case
|
||||
EXPECT_EQ(resC.GetInt(), 121); // 121: test case
|
||||
#ifdef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
int x = 7;
|
||||
double y = 1125899906842624;
|
||||
auto resD = fn(JSTaggedValue(x).GetRawData(), JSTaggedValue(y).GetRawData());
|
||||
@@ -380,21 +353,23 @@ HWTEST_F_L0(StubTest, FastMulTest)
|
||||
auto resG = fn(JSTaggedValue(x1).GetRawData(), JSTaggedValue(y1).GetRawData());
|
||||
auto expectedG = FastRuntimeStub::FastMul(JSTaggedValue(x1), JSTaggedValue(y1));
|
||||
EXPECT_EQ(resG, expectedG);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ECMASCRIPT_ENABLE_SPECIFIC_STUBS
|
||||
HWTEST_F_L0(StubTest, FastDivTest)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastDiv));
|
||||
Circuit netOfGates;
|
||||
FastDivStub optimizer(&netOfGates);
|
||||
FastDivStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto fn = reinterpret_cast<JSTaggedValue (*)(int64_t, int64_t)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
// test normal Division operation
|
||||
@@ -430,33 +405,32 @@ HWTEST_F_L0(StubTest, FastModTest)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastMod));
|
||||
Circuit netOfGates;
|
||||
FastModStub optimizer(&netOfGates);
|
||||
FastModStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
LLVMDumpModule(module);
|
||||
auto engine = assembler.GetEngine();
|
||||
uint64_t stub1Code = LLVMGetFunctionAddress(engine, "FastModStub");
|
||||
std::map<uint64_t, std::string> addr2name = {{stub1Code, "stub1"}};
|
||||
assembler.Disassemble(addr2name);
|
||||
auto fn = reinterpret_cast<JSTaggedValue (*)(JSThread *, int64_t, int64_t)>(
|
||||
auto fn = reinterpret_cast<JSTaggedValue (*)(uintptr_t, int64_t, int64_t)>(
|
||||
assembler.GetFuncPtrFromCompiledModule(function));
|
||||
// test left, right are all integer
|
||||
int x = 7;
|
||||
int y = 3;
|
||||
auto result = fn(thread, JSTaggedValue(x).GetRawData(), JSTaggedValue(y).GetRawData());
|
||||
auto result = fn(thread->GetGlueAddr(), JSTaggedValue(x).GetRawData(), JSTaggedValue(y).GetRawData());
|
||||
JSTaggedValue expectRes = FastRuntimeStub::FastMod(JSTaggedValue(x), JSTaggedValue(y));
|
||||
EXPECT_EQ(result, expectRes);
|
||||
|
||||
// test y == 0.0 || std::isnan(y) || std::isnan(x) || std::isinf(x) return NAN_VALUE
|
||||
double x2 = 7.3;
|
||||
int y2 = base::NAN_VALUE;
|
||||
auto result2 = fn(thread, JSTaggedValue(x2).GetRawData(), JSTaggedValue(y2).GetRawData());
|
||||
auto result2 = fn(thread->GetGlueAddr(), JSTaggedValue(x2).GetRawData(), JSTaggedValue(y2).GetRawData());
|
||||
auto expectRes2 = FastRuntimeStub::FastMod(JSTaggedValue(x2), JSTaggedValue(y2));
|
||||
EXPECT_EQ(result2, expectRes2);
|
||||
LOG_ECMA(INFO) << "result2 for FastMod(7, 'helloworld') = " << result2.GetRawData();
|
||||
@@ -465,14 +439,14 @@ HWTEST_F_L0(StubTest, FastModTest)
|
||||
// // test modular operation under normal conditions
|
||||
double x3 = 33.0;
|
||||
double y3 = 44.0;
|
||||
auto result3 = fn(thread, JSTaggedValue(x3).GetRawData(), JSTaggedValue(y3).GetRawData());
|
||||
auto result3 = fn(thread->GetGlueAddr(), JSTaggedValue(x3).GetRawData(), JSTaggedValue(y3).GetRawData());
|
||||
auto expectRes3 = FastRuntimeStub::FastMod(JSTaggedValue(x3), JSTaggedValue(y3));
|
||||
EXPECT_EQ(result3, expectRes3);
|
||||
|
||||
// test x == 0.0 || std::isinf(y) return x
|
||||
double x4 = base::NAN_VALUE;
|
||||
int y4 = 7;
|
||||
auto result4 = fn(thread, JSTaggedValue(x4).GetRawData(), JSTaggedValue(y4).GetRawData());
|
||||
auto result4 = fn(thread->GetGlueAddr(), JSTaggedValue(x4).GetRawData(), JSTaggedValue(y4).GetRawData());
|
||||
auto expectRes4 = FastRuntimeStub::FastMod(JSTaggedValue(x4), JSTaggedValue(y4));
|
||||
|
||||
LOG_ECMA(INFO) << "result4 for FastMod(base::NAN_VALUE, 7) = " << result4.GetRawData();
|
||||
@@ -483,7 +457,7 @@ HWTEST_F_L0(StubTest, FastModTest)
|
||||
int x5 = 7;
|
||||
auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory();
|
||||
auto y5 = factory->NewFromStdString("hello world");
|
||||
auto result5 = fn(thread, JSTaggedValue(x5).GetRawData(), y5.GetTaggedValue().GetRawData());
|
||||
auto result5 = fn(thread->GetGlueAddr(), JSTaggedValue(x5).GetRawData(), y5.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(result5, JSTaggedValue::Hole());
|
||||
auto expectRes5 = FastRuntimeStub::FastMod(JSTaggedValue(x5), y5.GetTaggedValue());
|
||||
LOG_ECMA(INFO) << "result1 for FastMod(7, 'helloworld') = " << result5.GetRawData();
|
||||
@@ -495,51 +469,78 @@ HWTEST_F_L0(StubTest, FastFindOwnElementStub)
|
||||
auto module = stubModule.GetModule();
|
||||
auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(FindOwnElement));
|
||||
Circuit netOfGates;
|
||||
FindOwnElementStub optimizer(&netOfGates);
|
||||
FindOwnElementStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
}
|
||||
|
||||
HWTEST_F_L0(StubTest, FunctionCallInternal)
|
||||
HWTEST_F_L0(StubTest, TryLoadICByName)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(FunctionCallInternal));
|
||||
auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(TryLoadICByName));
|
||||
Circuit netOfGates;
|
||||
FunctionCallInternalStub optimizer(&netOfGates);
|
||||
TryLoadICByNameStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
}
|
||||
|
||||
HWTEST_F_L0(StubTest, GetElementStub)
|
||||
HWTEST_F_L0(StubTest, TryLoadICByValue)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(FindOwnElement));
|
||||
auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(TryLoadICByValue));
|
||||
Circuit netOfGates;
|
||||
FindOwnElementStub findOptimizer(&netOfGates);
|
||||
findOptimizer.GenerateCircuit();
|
||||
TryLoadICByValueStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction);
|
||||
llvmBuilder.Build();
|
||||
Circuit getNetOfGates;
|
||||
GetElementStub getOptimizer(&getNetOfGates);
|
||||
getOptimizer.GenerateCircuit();
|
||||
getNetOfGates.PrintAllGates();
|
||||
auto getCfg = Scheduler::Run(&getNetOfGates);
|
||||
PrintCircuitByBasicBlock(getCfg, getNetOfGates);
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
}
|
||||
|
||||
HWTEST_F_L0(StubTest, TryStoreICByName)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(TryStoreICByName));
|
||||
Circuit netOfGates;
|
||||
TryStoreICByNameStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
}
|
||||
|
||||
HWTEST_F_L0(StubTest, TryStoreICByValue)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(TryStoreICByValue));
|
||||
Circuit netOfGates;
|
||||
TryStoreICByValueStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
}
|
||||
|
||||
@@ -548,16 +549,16 @@ HWTEST_F_L0(StubTest, FindOwnElement2Stub)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FindOwnElement2));
|
||||
Circuit netOfGates;
|
||||
FindOwnElement2Stub optimizer(&netOfGates);
|
||||
FindOwnElement2Stub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto *findOwnElement2Ptr = reinterpret_cast<JSTaggedValue (*)(JSThread *, TaggedArray *, uint32_t, bool,
|
||||
auto *findOwnElement2Ptr = reinterpret_cast<JSTaggedValue (*)(uintptr_t, TaggedArray *, uint32_t, bool,
|
||||
PropertyAttributes *, uint32_t *)>(
|
||||
reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(function)));
|
||||
auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory();
|
||||
@@ -571,28 +572,12 @@ HWTEST_F_L0(StubTest, FindOwnElement2Stub)
|
||||
uint32_t indexOrEntry;
|
||||
bool isDict = elements->IsDictionaryMode();
|
||||
assembler.Disassemble();
|
||||
JSTaggedValue resVal = findOwnElement2Ptr(thread, elements, 1, isDict, &attr, &indexOrEntry);
|
||||
JSTaggedValue resVal = findOwnElement2Ptr(thread->GetGlueAddr(), elements, 1, isDict, &attr, &indexOrEntry);
|
||||
EXPECT_EQ(resVal.GetNumber(), x);
|
||||
resVal = findOwnElement2Ptr(thread, elements, 10250, isDict, &attr, &indexOrEntry);
|
||||
resVal = findOwnElement2Ptr(thread->GetGlueAddr(), elements, 10250, isDict, &attr, &indexOrEntry);
|
||||
EXPECT_EQ(resVal.GetNumber(), y);
|
||||
}
|
||||
|
||||
HWTEST_F_L0(StubTest, SetElementStub)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(SetElement));
|
||||
Circuit netOfGates;
|
||||
SetElementStub optimizer(&netOfGates);
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
assembler.Run();
|
||||
}
|
||||
|
||||
struct ThreadTy {
|
||||
intptr_t magic; // 0x11223344
|
||||
intptr_t fp;
|
||||
@@ -733,7 +718,7 @@ HWTEST_F_L0(StubTest, JSEntryTest)
|
||||
{
|
||||
std::cout << " ---------- JSEntryTest ------------- " << std::endl;
|
||||
LLVMModuleRef module = LLVMModuleCreateWithName("simple_module");
|
||||
LLVMSetTarget(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMSetTarget(module, TripleConst::GetLLVMAmd64Triple());
|
||||
LLVMBuilderRef builder = LLVMCreateBuilder();
|
||||
LLVMContextRef context = LLVMGetGlobalContext();
|
||||
|
||||
@@ -842,11 +827,10 @@ HWTEST_F_L0(StubTest, JSEntryTest)
|
||||
LLVMBuildCall(builder, runtimeFunc2, argValue.data(), 1, "");
|
||||
retVal = LLVMConstInt(LLVMInt64Type(), 3, false);
|
||||
LLVMBuildRet(builder, retVal);
|
||||
LLVMDumpModule(module);
|
||||
char *error = nullptr;
|
||||
LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
|
||||
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto engine = assembler.GetEngine();
|
||||
uint64_t stub1Code = LLVMGetFunctionAddress(engine, "stub1");
|
||||
@@ -882,7 +866,7 @@ HWTEST_F_L0(StubTest, Prologue)
|
||||
{
|
||||
std::cout << " ---------- Prologue ------------- " << std::endl;
|
||||
LLVMModuleRef module = LLVMModuleCreateWithName("simple_module");
|
||||
LLVMSetTarget(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMSetTarget(module, TripleConst::GetLLVMAmd64Triple());
|
||||
LLVMBuilderRef builder = LLVMCreateBuilder();
|
||||
// struct ThreadTy
|
||||
LLVMTypeRef paramTys0[] = {
|
||||
@@ -915,12 +899,10 @@ HWTEST_F_L0(StubTest, Prologue)
|
||||
std::vector<LLVMValueRef> args = {value0, value1};
|
||||
auto retVal = LLVMBuildCall(builder, bar, args.data(), 2, "");
|
||||
LLVMBuildRet(builder, retVal);
|
||||
|
||||
LLVMDumpModule(module);
|
||||
char *error = nullptr;
|
||||
LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
|
||||
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto engine = assembler.GetEngine();
|
||||
uint64_t mainCode = LLVMGetFunctionAddress(engine, "main");
|
||||
@@ -941,7 +923,7 @@ HWTEST_F_L0(StubTest, CEntryFp)
|
||||
{
|
||||
std::cout << " ---------- CEntryFp ------------- " << std::endl;
|
||||
LLVMModuleRef module = LLVMModuleCreateWithName("simple_module");
|
||||
LLVMSetTarget(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMSetTarget(module, TripleConst::GetLLVMAmd64Triple());
|
||||
LLVMBuilderRef builder = LLVMCreateBuilder();
|
||||
LLVMContextRef context = LLVMGetGlobalContext();
|
||||
|
||||
@@ -965,7 +947,6 @@ HWTEST_F_L0(StubTest, CEntryFp)
|
||||
std::vector<LLVMValueRef> indexes1 = {c0, c0};
|
||||
std::vector<LLVMValueRef> indexes2 = {c0, c1};
|
||||
LLVMValueRef gep1 = LLVMBuildGEP2(builder, threadTy, value, indexes1.data(), indexes1.size(), "");
|
||||
LLVMDumpValue(gep1);
|
||||
std::cout << std::endl;
|
||||
LLVMValueRef gep2 = LLVMBuildGEP2(builder, threadTy, value, indexes2.data(), indexes2.size(), "fpAddr");
|
||||
LLVMBuildStore(builder, LLVMConstInt(LLVMInt64Type(), 0x11223344, false), gep1);
|
||||
@@ -991,12 +972,10 @@ HWTEST_F_L0(StubTest, CEntryFp)
|
||||
std::cout << std::endl;
|
||||
LLVMValueRef retVal = LLVMBuildCall(builder, runTimeFunc, argValue.data(), 1, "");
|
||||
LLVMBuildRet(builder, retVal);
|
||||
|
||||
LLVMDumpModule(module);
|
||||
char *error = nullptr;
|
||||
LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
|
||||
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto engine = assembler.GetEngine();
|
||||
uint64_t nativeCode = LLVMGetFunctionAddress(engine, "main");
|
||||
@@ -1034,19 +1013,16 @@ HWTEST_F_L0(StubTest, LoadGCIRTest)
|
||||
return;
|
||||
}
|
||||
LLVMModuleRef module = LLVMCloneModule(wrap(rawModule.get()));
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto engine = assembler.GetEngine();
|
||||
LLVMValueRef function = LLVMGetNamedFunction(module, "main");
|
||||
LLVMDumpValue(function);
|
||||
|
||||
auto *mainPtr = reinterpret_cast<int (*)()>(LLVMGetPointerToGlobal(engine, function));
|
||||
uint8_t *ptr = assembler.GetStackMapsSection();
|
||||
LLVMStackMapParser::GetInstance().CalculateStackMap(ptr);
|
||||
LLVMStackMapParser::GetInstance().Print();
|
||||
|
||||
assembler.Disassemble();
|
||||
LLVMDumpModule(module);
|
||||
int value = reinterpret_cast<int (*)()>(mainPtr)();
|
||||
std::cout << " value:" << value << std::endl;
|
||||
}
|
||||
@@ -1061,14 +1037,13 @@ void DoSafepoint()
|
||||
uintptr_t returnAddr = *(rbp + 1);
|
||||
uintptr_t *rsp = rbp + 2; // move 2 steps from rbp to get rsp
|
||||
rbp = reinterpret_cast<uintptr_t *>(*rbp);
|
||||
DwarfRegAndOffsetTypeVector infos;
|
||||
bool found = LLVMStackMapParser::GetInstance().StackMapByAddr(returnAddr, infos);
|
||||
if (found) {
|
||||
for (auto &info : infos) {
|
||||
const DwarfRegAndOffsetTypeVector *infos = LLVMStackMapParser::GetInstance().StackMapByAddr(returnAddr);
|
||||
if (infos != nullptr) {
|
||||
for (auto &info : *infos) {
|
||||
uintptr_t **address = nullptr;
|
||||
if (info.first == SP_DWARF_REG_NUM) {
|
||||
if (info.first == FrameConst::SP_DWARF_REG_NUM) {
|
||||
address = reinterpret_cast<uintptr_t **>(reinterpret_cast<uint8_t *>(rsp) + info.second);
|
||||
} else if (info.first == FP_DWARF_REG_NUM) {
|
||||
} else if (info.first == FrameConst::FP_DWARF_REG_NUM) {
|
||||
address = reinterpret_cast<uintptr_t **>(reinterpret_cast<uint8_t *>(rbp) + info.second);
|
||||
}
|
||||
// print ref and vlue for debug
|
||||
@@ -1090,16 +1065,16 @@ HWTEST_F_L0(StubTest, GetPropertyByIndexStub)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByIndex));
|
||||
Circuit netOfGates;
|
||||
GetPropertyByIndexStub optimizer(&netOfGates);
|
||||
GetPropertyByIndexStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto *getpropertyByIndex = reinterpret_cast<JSTaggedValue (*)(JSThread *, JSTaggedValue, uint32_t)>(
|
||||
auto *getpropertyByIndex = reinterpret_cast<JSTaggedValue (*)(uintptr_t, JSTaggedValue, uint32_t)>(
|
||||
reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(function)));
|
||||
auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSObject> obj = factory->NewEmptyJSObject();
|
||||
@@ -1108,9 +1083,9 @@ HWTEST_F_L0(StubTest, GetPropertyByIndexStub)
|
||||
FastRuntimeStub::SetOwnElement(thread, obj.GetTaggedValue(), 1, JSTaggedValue(x));
|
||||
FastRuntimeStub::SetOwnElement(thread, obj.GetTaggedValue(), 10250, JSTaggedValue(y));
|
||||
assembler.Disassemble();
|
||||
JSTaggedValue resVal = getpropertyByIndex(thread, obj.GetTaggedValue(), 1);
|
||||
JSTaggedValue resVal = getpropertyByIndex(thread->GetGlueAddr(), obj.GetTaggedValue(), 1);
|
||||
EXPECT_EQ(resVal.GetNumber(), x);
|
||||
resVal = getpropertyByIndex(thread, obj.GetTaggedValue(), 10250);
|
||||
resVal = getpropertyByIndex(thread->GetGlueAddr(), obj.GetTaggedValue(), 10250);
|
||||
EXPECT_EQ(resVal.GetNumber(), y);
|
||||
}
|
||||
|
||||
@@ -1119,7 +1094,7 @@ HWTEST_F_L0(StubTest, SetPropertyByIndexStub)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(SetPropertyByIndex));
|
||||
Circuit netOfGates;
|
||||
SetPropertyByIndexStub optimizer(&netOfGates);
|
||||
SetPropertyByIndexStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
bool result = Verifier::Run(&netOfGates);
|
||||
@@ -1128,9 +1103,9 @@ HWTEST_F_L0(StubTest, SetPropertyByIndexStub)
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto *setpropertyByIndex = reinterpret_cast<JSTaggedValue (*)(JSThread *, JSTaggedValue, uint32_t, JSTaggedValue)>(
|
||||
auto *setpropertyByIndex = reinterpret_cast<JSTaggedValue (*)(uintptr_t, JSTaggedValue, uint32_t, JSTaggedValue)>(
|
||||
reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(function)));
|
||||
auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSArray> array = factory->NewJSArray();
|
||||
@@ -1139,7 +1114,7 @@ HWTEST_F_L0(StubTest, SetPropertyByIndexStub)
|
||||
array->SetArrayLength(thread, 20);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
auto taggedArray = array.GetTaggedValue();
|
||||
setpropertyByIndex(thread, taggedArray, i, JSTaggedValue(i));
|
||||
setpropertyByIndex(thread->GetGlueAddr(), taggedArray, i, JSTaggedValue(i));
|
||||
}
|
||||
for (int i = 0; i < 20; i++) {
|
||||
EXPECT_EQ(JSTaggedValue(i),
|
||||
@@ -1152,7 +1127,7 @@ HWTEST_F_L0(StubTest, GetPropertyByNameStub)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByName));
|
||||
Circuit netOfGates;
|
||||
GetPropertyByNameStub optimizer(&netOfGates);
|
||||
GetPropertyByNameStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
bool result = Verifier::Run(&netOfGates);
|
||||
@@ -1161,32 +1136,67 @@ HWTEST_F_L0(StubTest, GetPropertyByNameStub)
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto *getPropertyByNamePtr = reinterpret_cast<JSTaggedValue (*)(JSThread *, uint64_t, uint64_t)>(
|
||||
auto *getPropertyByNamePtr = reinterpret_cast<JSTaggedValue (*)(uintptr_t, uint64_t, uint64_t)>(
|
||||
reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(function)));
|
||||
auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSObject> obj = factory->NewEmptyJSObject();
|
||||
int x = 213;
|
||||
int x = 256;
|
||||
int y = 10;
|
||||
JSHandle<JSTaggedValue> strA(factory->NewFromCanBeCompressString("a"));
|
||||
JSHandle<JSTaggedValue> strBig(factory->NewFromCanBeCompressString("biggest"));
|
||||
FastRuntimeStub::SetPropertyByName(thread, obj.GetTaggedValue(), strA.GetTaggedValue(), JSTaggedValue(x));
|
||||
FastRuntimeStub::SetPropertyByName(thread, obj.GetTaggedValue(), strBig.GetTaggedValue(), JSTaggedValue(y));
|
||||
assembler.Disassemble();
|
||||
JSTaggedValue resVal = getPropertyByNamePtr(thread, obj.GetTaggedValue().GetRawData(),
|
||||
JSTaggedValue resVal = getPropertyByNamePtr(thread->GetGlueAddr(), obj.GetTaggedValue().GetRawData(),
|
||||
strA.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resVal.GetNumber(), x);
|
||||
resVal = getPropertyByNamePtr(thread, obj.GetTaggedValue().GetRawData(), strBig.GetTaggedValue().GetRawData());
|
||||
resVal = getPropertyByNamePtr(thread->GetGlueAddr(), obj.GetTaggedValue().GetRawData(),
|
||||
strBig.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resVal.GetNumber(), y);
|
||||
}
|
||||
|
||||
#ifdef ARK_GC_SUPPORT
|
||||
HWTEST_F_L0(StubTest, SetPropertyByNameStub)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(SetPropertyByName));
|
||||
Circuit netOfGates;
|
||||
SetPropertyByNameStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
assembler.Disassemble();
|
||||
auto *setPropertyByName = reinterpret_cast<JSTaggedValue (*)(uintptr_t, JSTaggedValue,
|
||||
JSTaggedValue, JSTaggedValue, bool)>
|
||||
(reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(function)));
|
||||
auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSObject> obj = factory->NewEmptyJSObject();
|
||||
int x = 256;
|
||||
int y = 10;
|
||||
JSHandle<JSTaggedValue> strA(factory->NewFromCanBeCompressString("hello"));
|
||||
JSHandle<JSTaggedValue> strBig(factory->NewFromCanBeCompressString("biggest"));
|
||||
setPropertyByName(thread->GetGlueAddr(), obj.GetTaggedValue(), strA.GetTaggedValue(), JSTaggedValue(x), false);
|
||||
setPropertyByName(thread->GetGlueAddr(), obj.GetTaggedValue(), strBig.GetTaggedValue(), JSTaggedValue(y), false);
|
||||
auto resA = FastRuntimeStub::GetPropertyByName(thread, obj.GetTaggedValue(), strA.GetTaggedValue());
|
||||
EXPECT_EQ(resA.GetNumber(), x);
|
||||
auto resB = FastRuntimeStub::GetPropertyByName(thread, obj.GetTaggedValue(), strBig.GetTaggedValue());
|
||||
EXPECT_EQ(resB.GetNumber(), y);
|
||||
}
|
||||
#endif
|
||||
|
||||
HWTEST_F_L0(StubTest, GetPropertyByValueStub)
|
||||
{
|
||||
auto module = stubModule.GetModule();
|
||||
LLVMValueRef getPropertyByIndexfunction = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByIndex));
|
||||
Circuit netOfGates2;
|
||||
GetPropertyByIndexStub getPropertyByIndexStub(&netOfGates2);
|
||||
GetPropertyByIndexStub getPropertyByIndexStub(&netOfGates2, TripleConst::GetLLVMAmd64Triple());
|
||||
getPropertyByIndexStub.GenerateCircuit();
|
||||
netOfGates2.PrintAllGates();
|
||||
auto cfg2 = Scheduler::Run(&netOfGates2);
|
||||
@@ -1195,7 +1205,7 @@ HWTEST_F_L0(StubTest, GetPropertyByValueStub)
|
||||
|
||||
LLVMValueRef getPropertyByNamefunction = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByName));
|
||||
Circuit netOfGates1;
|
||||
GetPropertyByNameStub getPropertyByNameStub(&netOfGates1);
|
||||
GetPropertyByNameStub getPropertyByNameStub(&netOfGates1, TripleConst::GetLLVMAmd64Triple());
|
||||
getPropertyByNameStub.GenerateCircuit();
|
||||
bool result = Verifier::Run(&netOfGates1);
|
||||
ASSERT_TRUE(result);
|
||||
@@ -1205,28 +1215,23 @@ HWTEST_F_L0(StubTest, GetPropertyByValueStub)
|
||||
|
||||
LLVMValueRef function = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByValue));
|
||||
Circuit netOfGates;
|
||||
GetPropertyByValueStub optimizer(&netOfGates);
|
||||
GetPropertyByValueStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
result = Verifier::Run(&netOfGates);
|
||||
ASSERT_TRUE(result);
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) {
|
||||
std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":"
|
||||
<< std::endl;
|
||||
for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) {
|
||||
netOfGates.Print(cfg[bbIdx][instIdx - 1]);
|
||||
}
|
||||
}
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
auto *getPropertyByValuePtr = reinterpret_cast<JSTaggedValue (*)(JSThread *, uint64_t, uint64_t)>(
|
||||
auto *getPropertyByValuePtr = reinterpret_cast<JSTaggedValue (*)(uintptr_t, uint64_t, uint64_t)>(
|
||||
reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(function)));
|
||||
auto *getPropertyByNamePtr = reinterpret_cast<JSTaggedValue (*)(JSThread *, uint64_t, uint64_t)>(
|
||||
auto *getPropertyByNamePtr = reinterpret_cast<JSTaggedValue (*)(uintptr_t, uint64_t, uint64_t)>(
|
||||
reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(getPropertyByNamefunction)));
|
||||
auto *getpropertyByIndexPtr = reinterpret_cast<JSTaggedValue (*)(JSThread *, JSTaggedValue, uint32_t)>(
|
||||
auto *getpropertyByIndexPtr = reinterpret_cast<JSTaggedValue (*)(uintptr_t, JSTaggedValue, uint32_t)>(
|
||||
reinterpret_cast<uintptr_t>(assembler.GetFuncPtrFromCompiledModule(getPropertyByIndexfunction)));
|
||||
|
||||
thread->SetFastStubEntry(FAST_STUB_ID(GetPropertyByIndex), reinterpret_cast<uintptr_t>(getpropertyByIndexPtr));
|
||||
@@ -1248,24 +1253,28 @@ HWTEST_F_L0(StubTest, GetPropertyByValueStub)
|
||||
FastRuntimeStub::SetPropertyByName(thread, obj.GetTaggedValue(), strBig.GetTaggedValue(), JSTaggedValue(y));
|
||||
assembler.Disassemble();
|
||||
|
||||
JSTaggedValue resVal1 = getPropertyByNamePtr(thread, obj.GetTaggedValue().GetRawData(),
|
||||
JSTaggedValue resVal1 = getPropertyByNamePtr(thread->GetGlueAddr(), obj.GetTaggedValue().GetRawData(),
|
||||
strA.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resVal1.GetNumber(), x);
|
||||
JSTaggedValue resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(),
|
||||
JSTaggedValue resVal = getPropertyByValuePtr(thread->GetGlueAddr(), obj.GetTaggedValue().GetRawData(),
|
||||
strA.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resVal.GetNumber(), x);
|
||||
resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), strBig.GetTaggedValue().GetRawData());
|
||||
resVal = getPropertyByValuePtr(thread->GetGlueAddr(), obj.GetTaggedValue().GetRawData(),
|
||||
strBig.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resVal.GetNumber(), y);
|
||||
resVal = getpropertyByIndexPtr(thread, obj.GetTaggedValue(), 1);
|
||||
resVal = getpropertyByIndexPtr(thread->GetGlueAddr(), obj.GetTaggedValue(), 1);
|
||||
EXPECT_EQ(resVal.GetNumber(), x);
|
||||
resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), JSTaggedValue(10250).GetRawData());
|
||||
resVal = getPropertyByValuePtr(thread->GetGlueAddr(), obj.GetTaggedValue().GetRawData(),
|
||||
JSTaggedValue(10250).GetRawData());
|
||||
EXPECT_EQ(resVal.GetNumber(), y);
|
||||
resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), strDigit.GetTaggedValue().GetRawData());
|
||||
resVal = getPropertyByValuePtr(thread->GetGlueAddr(), obj.GetTaggedValue().GetRawData(),
|
||||
strDigit.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resVal.GetNumber(), y);
|
||||
|
||||
JSHandle<JSTaggedValue> strHello(factory->NewFromCanBeCompressString("hello world"));
|
||||
double key = 4.29497e+09;
|
||||
resVal = getPropertyByValuePtr(thread, strHello.GetTaggedValue().GetRawData(), JSTaggedValue(key).GetRawData());
|
||||
resVal = getPropertyByValuePtr(thread->GetGlueAddr(), strHello.GetTaggedValue().GetRawData(),
|
||||
JSTaggedValue(key).GetRawData());
|
||||
EXPECT_EQ(resVal.GetRawData(), 0);
|
||||
}
|
||||
|
||||
@@ -1274,7 +1283,7 @@ HWTEST_F_L0(StubTest, FastTypeOfTest)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastTypeOf));
|
||||
Circuit netOfGates;
|
||||
FastTypeOfStub optimizer(&netOfGates);
|
||||
FastTypeOfStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
bool verRes = Verifier::Run(&netOfGates);
|
||||
@@ -1285,39 +1294,38 @@ HWTEST_F_L0(StubTest, FastTypeOfTest)
|
||||
llvmBuilder.Build();
|
||||
char *error = nullptr;
|
||||
LLVMVerifyModule(module, LLVMAbortProcessAction, &error);
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
LLVMDumpModule(module);
|
||||
auto *typeOfPtr =
|
||||
reinterpret_cast<JSTaggedValue (*)(JSThread *, uint64_t)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
reinterpret_cast<JSTaggedValue (*)(uintptr_t, uint64_t)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
|
||||
|
||||
// obj is JSTaggedValue::VALUE_TRUE
|
||||
JSTaggedValue resultVal = typeOfPtr(thread, JSTaggedValue::True().GetRawData());
|
||||
JSTaggedValue resultVal = typeOfPtr(thread->GetGlueAddr(), JSTaggedValue::True().GetRawData());
|
||||
JSTaggedValue expectResult = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::True());
|
||||
EXPECT_EQ(resultVal, globalConst->GetBooleanString());
|
||||
EXPECT_EQ(resultVal, expectResult);
|
||||
|
||||
// obj is JSTaggedValue::VALUE_FALSE
|
||||
JSTaggedValue resultVal2 = typeOfPtr(thread, JSTaggedValue::False().GetRawData());
|
||||
JSTaggedValue resultVal2 = typeOfPtr(thread->GetGlueAddr(), JSTaggedValue::False().GetRawData());
|
||||
JSTaggedValue expectResult2 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::False());
|
||||
EXPECT_EQ(resultVal2, globalConst->GetBooleanString());
|
||||
EXPECT_EQ(resultVal2, expectResult2);
|
||||
|
||||
// obj is JSTaggedValue::VALUE_NULL
|
||||
JSTaggedValue resultVal3 = typeOfPtr(thread, JSTaggedValue::Null().GetRawData());
|
||||
JSTaggedValue resultVal3 = typeOfPtr(thread->GetGlueAddr(), JSTaggedValue::Null().GetRawData());
|
||||
JSTaggedValue expectResult3 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::Null());
|
||||
EXPECT_EQ(resultVal3, globalConst->GetObjectString());
|
||||
EXPECT_EQ(resultVal3, expectResult3);
|
||||
|
||||
// obj is JSTaggedValue::VALUE_UNDEFINED
|
||||
JSTaggedValue resultVal4 = typeOfPtr(thread, JSTaggedValue::Undefined().GetRawData());
|
||||
JSTaggedValue resultVal4 = typeOfPtr(thread->GetGlueAddr(), JSTaggedValue::Undefined().GetRawData());
|
||||
JSTaggedValue expectResult4 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::Undefined());
|
||||
EXPECT_EQ(resultVal4, globalConst->GetUndefinedString());
|
||||
EXPECT_EQ(resultVal4, expectResult4);
|
||||
|
||||
// obj is IsNumber
|
||||
JSTaggedValue resultVal5 = typeOfPtr(thread, JSTaggedValue(5).GetRawData());
|
||||
JSTaggedValue resultVal5 = typeOfPtr(thread->GetGlueAddr(), JSTaggedValue(5).GetRawData());
|
||||
JSTaggedValue expectResult5 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue(5));
|
||||
EXPECT_EQ(resultVal5, globalConst->GetNumberString());
|
||||
EXPECT_EQ(resultVal5, expectResult5);
|
||||
@@ -1327,7 +1335,7 @@ HWTEST_F_L0(StubTest, FastTypeOfTest)
|
||||
JSHandle<EcmaString> str1 = factory->NewFromStdString("a");
|
||||
JSHandle<EcmaString> str2 = factory->NewFromStdString("a");
|
||||
JSTaggedValue expectResult6 = FastRuntimeStub::FastTypeOf(thread, str1.GetTaggedValue());
|
||||
JSTaggedValue resultVal6 = typeOfPtr(thread, str2.GetTaggedValue().GetRawData());
|
||||
JSTaggedValue resultVal6 = typeOfPtr(thread->GetGlueAddr(), str2.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resultVal6, globalConst->GetStringString());
|
||||
EXPECT_EQ(resultVal6, expectResult6);
|
||||
|
||||
@@ -1335,7 +1343,7 @@ HWTEST_F_L0(StubTest, FastTypeOfTest)
|
||||
JSHandle<GlobalEnv> globalEnv = JSThread::Cast(thread)->GetEcmaVM()->GetGlobalEnv();
|
||||
JSTaggedValue symbol = globalEnv->GetIteratorSymbol().GetTaggedValue();
|
||||
JSTaggedValue expectResult7= FastRuntimeStub::FastTypeOf(thread, symbol);
|
||||
JSTaggedValue resultVal7 = typeOfPtr(thread, symbol.GetRawData());
|
||||
JSTaggedValue resultVal7 = typeOfPtr(thread->GetGlueAddr(), symbol.GetRawData());
|
||||
EXPECT_EQ(resultVal7, globalConst->GetSymbolString());
|
||||
EXPECT_EQ(resultVal7, expectResult7);
|
||||
|
||||
@@ -1343,14 +1351,14 @@ HWTEST_F_L0(StubTest, FastTypeOfTest)
|
||||
JSHandle<JSPromiseReactionsFunction> resolveCallable =
|
||||
factory->CreateJSPromiseReactionsFunction(reinterpret_cast<void *>(BuiltinsPromiseHandler::Resolve));
|
||||
JSTaggedValue expectResult8= FastRuntimeStub::FastTypeOf(thread, resolveCallable.GetTaggedValue());
|
||||
JSTaggedValue resultVal8 = typeOfPtr(thread, resolveCallable.GetTaggedValue().GetRawData());
|
||||
JSTaggedValue resultVal8 = typeOfPtr(thread->GetGlueAddr(), resolveCallable.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resultVal8, globalConst->GetFunctionString());
|
||||
EXPECT_EQ(resultVal8, expectResult8);
|
||||
|
||||
// obj is heapObject
|
||||
JSHandle<JSObject> object = factory->NewEmptyJSObject();
|
||||
JSTaggedValue expectResult9= FastRuntimeStub::FastTypeOf(thread, object.GetTaggedValue());
|
||||
JSTaggedValue resultVal9 = typeOfPtr(thread, object.GetTaggedValue().GetRawData());
|
||||
JSTaggedValue resultVal9 = typeOfPtr(thread->GetGlueAddr(), object.GetTaggedValue().GetRawData());
|
||||
EXPECT_EQ(resultVal9, globalConst->GetObjectString());
|
||||
EXPECT_EQ(resultVal9, expectResult9);
|
||||
}
|
||||
@@ -1360,16 +1368,15 @@ HWTEST_F_L0(StubTest, FastEqualTest)
|
||||
auto module = stubModule.GetModule();
|
||||
auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastEqual));
|
||||
Circuit netOfGates;
|
||||
FastEqualStub optimizer(&netOfGates);
|
||||
FastEqualStub optimizer(&netOfGates, TripleConst::GetLLVMAmd64Triple());
|
||||
optimizer.GenerateCircuit();
|
||||
netOfGates.PrintAllGates();
|
||||
auto cfg = Scheduler::Run(&netOfGates);
|
||||
PrintCircuitByBasicBlock(cfg, netOfGates);
|
||||
LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function);
|
||||
llvmBuilder.Build();
|
||||
LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu");
|
||||
LLVMAssembler assembler(module, TripleConst::GetLLVMAmd64Triple());
|
||||
assembler.Run();
|
||||
LLVMDumpModule(module);
|
||||
auto fn = reinterpret_cast<JSTaggedValue (*)(int64_t, int64_t)>(assembler.GetFuncPtrFromCompiledModule(function));
|
||||
// test for 1 == 1
|
||||
auto resA = fn(JSTaggedValue(1).GetRawData(), JSTaggedValue(1).GetRawData());
|
||||
@@ -1423,4 +1430,5 @@ HWTEST_F_L0(StubTest, FastEqualTest)
|
||||
auto expectI = FastRuntimeStub::FastEqual(obj1.GetTaggedValue(), obj2.GetTaggedValue());
|
||||
EXPECT_EQ(resI, expectI);
|
||||
}
|
||||
#endif
|
||||
} // namespace panda::test
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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/compiler/triple.h"
|
||||
|
||||
namespace kungfu {
|
||||
const char *TripleConst::llvmAmd64Triple_ = "x86_64-unknown-linux-gnu";
|
||||
const char *TripleConst::llvmArm64Triple_ = "aarch64-unknown-linux-gnu";
|
||||
const char *TripleConst::llvmArm32Triple_ = "arm-unknown-linux-gnu";
|
||||
} // namespace kungfu
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef ECMASCRIPT_COMPILER_TRIPLE_H
|
||||
#define ECMASCRIPT_COMPILER_TRIPLE_H
|
||||
|
||||
#include <string>
|
||||
#include "ecmascript/compiler/compiler_macros.h"
|
||||
|
||||
namespace kungfu {
|
||||
class TripleConst {
|
||||
public:
|
||||
static const char *GetLLVMAmd64Triple()
|
||||
{
|
||||
return llvmAmd64Triple_;
|
||||
}
|
||||
static const char *GetLLVMArm64Triple()
|
||||
{
|
||||
return llvmArm64Triple_;
|
||||
}
|
||||
static const char *GetLLVMArm32Triple()
|
||||
{
|
||||
return llvmArm32Triple_;
|
||||
}
|
||||
|
||||
static const char *StringTripleToConst(const std::string &triple)
|
||||
{
|
||||
if (triple.compare(llvmAmd64Triple_) == 0) {
|
||||
return llvmAmd64Triple_;
|
||||
}
|
||||
if (triple.compare(llvmArm64Triple_) == 0) {
|
||||
return llvmArm64Triple_;
|
||||
}
|
||||
if (triple.compare(llvmArm32Triple_) == 0) {
|
||||
return llvmArm32Triple_;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static const char *llvmAmd64Triple_;
|
||||
static const char *llvmArm64Triple_;
|
||||
static const char *llvmArm32Triple_;
|
||||
};
|
||||
} // namespace kungfu
|
||||
#endif // ECMASCRIPT_COMPILER_TRIPLE_H
|
||||
@@ -22,11 +22,11 @@ namespace kungfu {
|
||||
using GateType = uint8_t;
|
||||
enum class TypeCode : GateType {
|
||||
// for AOT
|
||||
NOTYPE,
|
||||
JS_ANY,
|
||||
NOTYPE = 0,
|
||||
JS_NULL,
|
||||
JS_UNDEFINED,
|
||||
JS_BOOLEAN,
|
||||
JS_ANY,
|
||||
JS_NUMBER,
|
||||
JS_STRING,
|
||||
JS_BIGINT,
|
||||
@@ -43,8 +43,13 @@ enum class TypeCode : GateType {
|
||||
JS_FLOAT32ARRAY,
|
||||
JS_FLOAT64ARRAY,
|
||||
// for Stub
|
||||
POINTER_TYPE,
|
||||
TAGGED_POINTER_TYPE,
|
||||
TAGGED_POINTER,
|
||||
|
||||
JS_TYPE_START = JS_NULL,
|
||||
JS_TYPE_SPECIAL_START = JS_NULL,
|
||||
JS_TYPE_SPECIAL_STOP = JS_BOOLEAN,
|
||||
JS_TYPE_OBJECT_START = JS_ANY,
|
||||
JS_TYPE_OBJECT_STOP = JS_FLOAT64ARRAY,
|
||||
};
|
||||
|
||||
class Type {
|
||||
|
||||
@@ -23,16 +23,16 @@
|
||||
namespace kungfu {
|
||||
bool Verifier::RunDataIntegrityCheck(const Circuit *circuit)
|
||||
{
|
||||
std::unordered_set<AddrShift> gatesSet;
|
||||
std::vector<AddrShift> gatesList;
|
||||
std::unordered_set<GateRef> gatesSet;
|
||||
std::vector<GateRef> gatesList;
|
||||
gatesList.push_back(0);
|
||||
gatesSet.insert(0);
|
||||
size_t out = sizeof(Gate);
|
||||
AddrShift prevGate = 0;
|
||||
GateRef prevGate = 0;
|
||||
while (true) {
|
||||
AddrShift gate = circuit->SaveGatePtr(
|
||||
GateRef gate = circuit->SaveGatePtr(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
reinterpret_cast<const Out *>(circuit->LoadGatePtrConst(AddrShift(out)))->GetGateConst());
|
||||
reinterpret_cast<const Out *>(circuit->LoadGatePtrConst(GateRef(out)))->GetGateConst());
|
||||
if (gate < prevGate + static_cast<int64_t>(sizeof(Gate)) ||
|
||||
gate >= static_cast<int64_t>(circuit->GetCircuitDataSize())) {
|
||||
std::cerr << "[Verifier][Error] Circuit data is corrupted (bad next gate)" << std::endl;
|
||||
@@ -44,7 +44,7 @@ bool Verifier::RunDataIntegrityCheck(const Circuit *circuit)
|
||||
prevGate = gate;
|
||||
out += Gate::GetGateSize(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
reinterpret_cast<const Out *>(circuit->LoadGatePtrConst(AddrShift(out)))->GetIndex() + 1);
|
||||
reinterpret_cast<const Out *>(circuit->LoadGatePtrConst(GateRef(out)))->GetIndex() + 1);
|
||||
if (out == circuit->GetCircuitDataSize()) {
|
||||
break;
|
||||
}
|
||||
@@ -99,23 +99,27 @@ bool Verifier::RunDataIntegrityCheck(const Circuit *circuit)
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Circuit data integrity is verified" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunStateGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList)
|
||||
bool Verifier::RunStateGatesCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList)
|
||||
{
|
||||
for (const auto &bbGate : bbGatesList) {
|
||||
if (!circuit->Verify(bbGate)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] State gates input list schema is verified" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunCFGSoundnessCheck(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx)
|
||||
bool Verifier::RunCFGSoundnessCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx)
|
||||
{
|
||||
for (const auto &bbGate : bbGatesList) {
|
||||
for (const auto &predGate : circuit->GetInVector(bbGate)) {
|
||||
@@ -132,14 +136,16 @@ bool Verifier::RunCFGSoundnessCheck(const Circuit *circuit, const std::vector<Ad
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] CFG is sound" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunCFGIsDAGCheck(const Circuit *circuit)
|
||||
{
|
||||
circuit->AdvanceTime();
|
||||
std::function<bool(AddrShift)> dfs = [&](AddrShift cur) -> bool {
|
||||
std::function<bool(GateRef)> dfs = [&](GateRef cur) -> bool {
|
||||
if (circuit->GetOpCode(cur) == OpCode::LOOP_BACK) {
|
||||
return true;
|
||||
}
|
||||
@@ -171,12 +177,14 @@ bool Verifier::RunCFGIsDAGCheck(const Circuit *circuit)
|
||||
if (!dfs(root)) {
|
||||
return false;
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] CFG without loop back edges is directed acyclic graph" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunCFGReducibilityCheck(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
bool Verifier::RunCFGReducibilityCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor)
|
||||
{
|
||||
for (const auto &curGate : bbGatesList) {
|
||||
@@ -197,23 +205,27 @@ bool Verifier::RunCFGReducibilityCheck(const Circuit *circuit, const std::vector
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] CFG is reducible" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunFixedGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &fixedGatesList)
|
||||
bool Verifier::RunFixedGatesCheck(const Circuit *circuit, const std::vector<GateRef> &fixedGatesList)
|
||||
{
|
||||
for (const auto &fixedGate : fixedGatesList) {
|
||||
if (!circuit->Verify(fixedGate)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Fixed gates input list schema is verified" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunFixedGatesRelationsCheck(const Circuit *circuit, const std::vector<AddrShift> &fixedGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
bool Verifier::RunFixedGatesRelationsCheck(const Circuit *circuit, const std::vector<GateRef> &fixedGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor)
|
||||
{
|
||||
for (const auto &fixedGate : fixedGatesList) {
|
||||
@@ -238,15 +250,17 @@ bool Verifier::RunFixedGatesRelationsCheck(const Circuit *circuit, const std::ve
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Fixed gates relationship is consistent" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunFlowCyclesFind(const Circuit *circuit, std::vector<AddrShift> *schedulableGatesListPtr,
|
||||
const std::vector<AddrShift> &bbGatesList, const std::vector<AddrShift> &fixedGatesList)
|
||||
bool Verifier::RunFlowCyclesFind(const Circuit *circuit, std::vector<GateRef> *schedulableGatesListPtr,
|
||||
const std::vector<GateRef> &bbGatesList, const std::vector<GateRef> &fixedGatesList)
|
||||
{
|
||||
circuit->AdvanceTime();
|
||||
std::vector<AddrShift> startGateList;
|
||||
std::vector<GateRef> startGateList;
|
||||
for (const auto &gate : bbGatesList) {
|
||||
for (const auto &predGate : circuit->GetInVector(gate)) {
|
||||
if (circuit->GetOpCode(predGate).IsSchedulable()) {
|
||||
@@ -268,9 +282,9 @@ bool Verifier::RunFlowCyclesFind(const Circuit *circuit, std::vector<AddrShift>
|
||||
}
|
||||
}
|
||||
circuit->AdvanceTime();
|
||||
std::vector<AddrShift> cycleGatesList;
|
||||
AddrShift meet = -1;
|
||||
std::function<bool(AddrShift)> dfs = [&](AddrShift cur) -> bool {
|
||||
std::vector<GateRef> cycleGatesList;
|
||||
GateRef meet = -1;
|
||||
std::function<bool(GateRef)> dfs = [&](GateRef cur) -> bool {
|
||||
circuit->SetMark(cur, MarkCode::VISITED);
|
||||
schedulableGatesListPtr->push_back(cur);
|
||||
size_t numIns = circuit->LoadGatePtrConst(cur)->GetNumIns();
|
||||
@@ -316,22 +330,26 @@ bool Verifier::RunFlowCyclesFind(const Circuit *circuit, std::vector<AddrShift>
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Every directed data or depend flow cycles in circuit contain selectors" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunSchedulableGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &schedulableGatesList)
|
||||
bool Verifier::RunSchedulableGatesCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList)
|
||||
{
|
||||
for (const auto &schedulableGate : schedulableGatesList) {
|
||||
if (!circuit->Verify(schedulableGate)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Schedulable gates input list schema is verified" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunPrologGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &schedulableGatesList)
|
||||
bool Verifier::RunPrologGatesCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList)
|
||||
{
|
||||
for (const auto &schedulableGate : schedulableGatesList) {
|
||||
for (const auto &predGate : circuit->GetInVector(schedulableGate)) {
|
||||
@@ -342,17 +360,19 @@ bool Verifier::RunPrologGatesCheck(const Circuit *circuit, const std::vector<Add
|
||||
}
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Prolog gates input list schema is verified" << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Verifier::RunSchedulingBoundsCheck(const Circuit *circuit, const std::vector<AddrShift> &schedulableGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
bool Verifier::RunSchedulingBoundsCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor,
|
||||
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor)
|
||||
{
|
||||
// check existence of scheduling upper bound
|
||||
std::unordered_map<AddrShift, size_t> upperBound;
|
||||
std::unordered_map<GateRef, size_t> upperBound;
|
||||
{
|
||||
auto result =
|
||||
Scheduler::CalculateSchedulingUpperBound(circuit, bbGatesAddrToIdx, isAncestor, schedulableGatesList);
|
||||
@@ -360,14 +380,18 @@ bool Verifier::RunSchedulingBoundsCheck(const Circuit *circuit, const std::vecto
|
||||
return false;
|
||||
}
|
||||
upperBound = result.value();
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Scheduling upper bounds of all schedulable gates exist" << std::endl;
|
||||
#endif
|
||||
}
|
||||
// check existence of scheduling lower bound
|
||||
std::unordered_map<AddrShift, size_t> lowerBound;
|
||||
std::unordered_map<GateRef, size_t> lowerBound;
|
||||
{
|
||||
auto result = Scheduler::CalculateSchedulingLowerBound(circuit, bbGatesAddrToIdx, lowestCommonAncestor);
|
||||
lowerBound = result.value();
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Scheduling lower bounds of all schedulable gates exist" << std::endl;
|
||||
#endif
|
||||
}
|
||||
// check consistency of lower bound and upper bound
|
||||
{
|
||||
@@ -381,14 +405,16 @@ bool Verifier::RunSchedulingBoundsCheck(const Circuit *circuit, const std::vecto
|
||||
std::cerr << "Lower bound is BB_" << lowerBound.at(item.first) << std::endl;
|
||||
}
|
||||
}
|
||||
#if ECMASCRIPT_ENABLE_COMPILER_LOG
|
||||
std::cerr << "[Verifier][Pass] Bounds of all schedulable gates are consistent" << std::endl;
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<AddrShift> Verifier::FindFixedGates(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList)
|
||||
std::vector<GateRef> Verifier::FindFixedGates(const Circuit *circuit, const std::vector<GateRef> &bbGatesList)
|
||||
{
|
||||
std::vector<AddrShift> fixedGatesList;
|
||||
std::vector<GateRef> fixedGatesList;
|
||||
for (const auto &bbGate : bbGatesList) {
|
||||
for (const auto &succGate : circuit->GetOutVector(bbGate)) {
|
||||
if (circuit->GetOpCode(succGate).IsFixed()) {
|
||||
@@ -404,8 +430,8 @@ bool Verifier::Run(const Circuit *circuit)
|
||||
if (!RunDataIntegrityCheck(circuit)) {
|
||||
return false;
|
||||
}
|
||||
std::vector<AddrShift> bbGatesList;
|
||||
std::unordered_map<AddrShift, size_t> bbGatesAddrToIdx;
|
||||
std::vector<GateRef> bbGatesList;
|
||||
std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
|
||||
std::vector<size_t> immDom;
|
||||
std::tie(bbGatesList, bbGatesAddrToIdx, immDom) = Scheduler::CalculateDominatorTree(circuit);
|
||||
std::cerr << std::dec;
|
||||
@@ -463,14 +489,14 @@ bool Verifier::Run(const Circuit *circuit)
|
||||
if (!RunCFGReducibilityCheck(circuit, bbGatesList, bbGatesAddrToIdx, isAncestor)) {
|
||||
return false;
|
||||
}
|
||||
std::vector<AddrShift> fixedGatesList = FindFixedGates(circuit, bbGatesList);
|
||||
std::vector<GateRef> fixedGatesList = FindFixedGates(circuit, bbGatesList);
|
||||
if (!RunFixedGatesCheck(circuit, fixedGatesList)) {
|
||||
return false;
|
||||
}
|
||||
if (!RunFixedGatesRelationsCheck(circuit, fixedGatesList, bbGatesAddrToIdx, isAncestor)) {
|
||||
return false;
|
||||
}
|
||||
std::vector<AddrShift> schedulableGatesList;
|
||||
std::vector<GateRef> schedulableGatesList;
|
||||
if (!RunFlowCyclesFind(circuit, &schedulableGatesList, bbGatesList, fixedGatesList)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -28,27 +28,27 @@ namespace kungfu {
|
||||
class Verifier {
|
||||
public:
|
||||
static bool RunDataIntegrityCheck(const Circuit *circuit);
|
||||
static bool RunStateGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList);
|
||||
static bool RunCFGSoundnessCheck(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx);
|
||||
static bool RunStateGatesCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList);
|
||||
static bool RunCFGSoundnessCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx);
|
||||
static bool RunCFGIsDAGCheck(const Circuit *circuit);
|
||||
static bool RunCFGReducibilityCheck(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
static bool RunCFGReducibilityCheck(const Circuit *circuit, const std::vector<GateRef> &bbGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor);
|
||||
static bool RunFixedGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &fixedGatesList);
|
||||
static bool RunFixedGatesRelationsCheck(const Circuit *circuit, const std::vector<AddrShift> &fixedGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
static bool RunFixedGatesCheck(const Circuit *circuit, const std::vector<GateRef> &fixedGatesList);
|
||||
static bool RunFixedGatesRelationsCheck(const Circuit *circuit, const std::vector<GateRef> &fixedGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor);
|
||||
static bool RunFlowCyclesFind(const Circuit *circuit, std::vector<AddrShift> *schedulableGatesListPtr,
|
||||
const std::vector<AddrShift> &bbGatesList,
|
||||
const std::vector<AddrShift> &fixedGatesList);
|
||||
static bool RunSchedulableGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &schedulableGatesList);
|
||||
static bool RunPrologGatesCheck(const Circuit *circuit, const std::vector<AddrShift> &schedulableGatesList);
|
||||
static bool RunSchedulingBoundsCheck(const Circuit *circuit, const std::vector<AddrShift> &schedulableGatesList,
|
||||
const std::unordered_map<AddrShift, size_t> &bbGatesAddrToIdx,
|
||||
static bool RunFlowCyclesFind(const Circuit *circuit, std::vector<GateRef> *schedulableGatesListPtr,
|
||||
const std::vector<GateRef> &bbGatesList,
|
||||
const std::vector<GateRef> &fixedGatesList);
|
||||
static bool RunSchedulableGatesCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList);
|
||||
static bool RunPrologGatesCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList);
|
||||
static bool RunSchedulingBoundsCheck(const Circuit *circuit, const std::vector<GateRef> &schedulableGatesList,
|
||||
const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
|
||||
const std::function<bool(size_t, size_t)> &isAncestor,
|
||||
const std::function<size_t(size_t, size_t)> &lowestCommonAncestor);
|
||||
static std::vector<AddrShift> FindFixedGates(const Circuit *circuit, const std::vector<AddrShift> &bbGatesList);
|
||||
static std::vector<GateRef> FindFixedGates(const Circuit *circuit, const std::vector<GateRef> &bbGatesList);
|
||||
static bool Run(const Circuit *circuit);
|
||||
};
|
||||
} // namespace kungfu
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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/cpu_profiler/cpu_profiler.h"
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <fstream>
|
||||
#include "ecmascript/platform/platform.h"
|
||||
namespace panda::ecmascript {
|
||||
CMap<JSMethod *, struct StackInfo> CpuProfiler::staticStackInfo_ = CMap<JSMethod *, struct StackInfo>();
|
||||
CpuProfiler *CpuProfiler::singleton_ = nullptr;
|
||||
sem_t CpuProfiler::sem_ = sem_t {};
|
||||
CMap<std::string, int> CpuProfiler::scriptIdMap_ = CMap<std::string, int>();
|
||||
CVector<JSMethod *> CpuProfiler::staticFrameStack_ = CVector<JSMethod *>();
|
||||
CpuProfiler::CpuProfiler()
|
||||
{
|
||||
generator_ = new ProfileGenerator();
|
||||
if (sem_init(&sem_, 0, 1) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sem_ init failed";
|
||||
}
|
||||
if (sem_wait(&sem_) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sem_ wait failed";
|
||||
}
|
||||
}
|
||||
|
||||
CpuProfiler *CpuProfiler::GetInstance()
|
||||
{
|
||||
if (CpuProfiler::singleton_ == nullptr) {
|
||||
CpuProfiler::singleton_ = new CpuProfiler();
|
||||
}
|
||||
return CpuProfiler::singleton_;
|
||||
}
|
||||
|
||||
void CpuProfiler::StartCpuProfiler(const EcmaVM *vm)
|
||||
{
|
||||
if (isOnly_) {
|
||||
return;
|
||||
}
|
||||
isOnly_ = true;
|
||||
#if ECMASCRIPT_ENABLE_ACTIVE_CPUPROFILER
|
||||
#else
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = &GetStackSignalHandler;
|
||||
if (sigemptyset(&sa.sa_mask) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "Parameter set signal set initialization and emptying failed";
|
||||
return;
|
||||
}
|
||||
sa.sa_flags = SA_RESTART;
|
||||
if (sigaction(SIGINT, &sa, nullptr) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sigaction failed to set signal";
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
time_t ts = ProfileProcessor::GetMicrosecondsTimeStamp();
|
||||
ts = ts % TIME_CHANGE;
|
||||
SetProfileStart(ts);
|
||||
Platform::GetCurrentPlatform()->PostTask(std::make_unique<ProfileProcessor>(generator_, vm, interval_));
|
||||
}
|
||||
|
||||
void CpuProfiler::StopCpuProfiler()
|
||||
{
|
||||
if (!isOnly_) {
|
||||
LOG(ERROR, RUNTIME) << "Do not execute stop cpuprofiler twice in a row";
|
||||
return;
|
||||
}
|
||||
isOnly_ = false;
|
||||
ProfileProcessor::SetIsStart(false);
|
||||
generator_->WriteMethodsAndSampleInfo(true);
|
||||
std::string profileName = GetProfileName();
|
||||
std::ofstream file;
|
||||
if (!profileName.empty()) {
|
||||
file.open(profileName.c_str());
|
||||
file << generator_->GetSampleData();
|
||||
file.close();
|
||||
}
|
||||
if (singleton_ != nullptr) {
|
||||
delete singleton_;
|
||||
singleton_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CpuProfiler::~CpuProfiler()
|
||||
{
|
||||
if (sem_destroy(&sem_) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sem_ destroy failed";
|
||||
}
|
||||
if (generator_ != nullptr) {
|
||||
delete generator_;
|
||||
generator_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CpuProfiler::SetProfileStart(time_t nowTimeStamp)
|
||||
{
|
||||
time_t ts = ProfileProcessor::GetMicrosecondsTimeStamp();
|
||||
ts = ts % TIME_CHANGE;
|
||||
struct CurrentProcessInfo currentProcessInfo = {0};
|
||||
GetCurrentProcessInfo(currentProcessInfo);
|
||||
std::string data = "";
|
||||
data = "[{\"args\":{\"data\":{\"frames\":[{\"processId\":" + std::to_string(currentProcessInfo.pid) + "}]"
|
||||
+ ",\"persistentIds\":true}},\"cat\":\"disabled-by-default-devtools.timeline\","
|
||||
+ "\"name\":\"TracingStartedInBrowser\",\"ph\":\"I\",\"pid\":"
|
||||
+ std::to_string(currentProcessInfo.pid) + ",\"s\":\"t\",\"tid\":"
|
||||
+ std::to_string(currentProcessInfo.tid) + ",\"ts\":"
|
||||
+ std::to_string(ts) + ",\"tts\":178460227},\n";
|
||||
ts = ProfileProcessor::GetMicrosecondsTimeStamp();
|
||||
ts = ts % TIME_CHANGE;
|
||||
data += "{\"args\":{\"data\":{\"startTime\":" + std::to_string(nowTimeStamp) + "}},"
|
||||
+ "\"cat\":\"disabled-by-default-v8.cpu_profiler\",\"id\":\"0x2\","
|
||||
+ "\"name\":\"Profile\",\"ph\":\"P\",\"pid\":"
|
||||
+ std::to_string(currentProcessInfo.pid) + ",\"tid\":"
|
||||
+ std::to_string(currentProcessInfo.tid) + ",\"ts\":"
|
||||
+ std::to_string(ts) + ",\"tts\":" + std::to_string(currentProcessInfo.tts)
|
||||
+ "},\n";
|
||||
generator_->SetStartsampleData(data);
|
||||
}
|
||||
|
||||
void CpuProfiler::GetCurrentProcessInfo(struct CurrentProcessInfo ¤tProcessInfo) const
|
||||
{
|
||||
currentProcessInfo.nowTimeStamp = ProfileProcessor::GetMicrosecondsTimeStamp() % TIME_CHANGE;
|
||||
currentProcessInfo.pid = getpid();
|
||||
currentProcessInfo.tid = syscall(SYS_gettid);
|
||||
struct timespec time = {0, 0};
|
||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||
currentProcessInfo.tts = time.tv_nsec / 1000; // 1000:Nanoseconds to milliseconds.
|
||||
}
|
||||
|
||||
void CpuProfiler::GetFrameStack(JSThread *thread)
|
||||
{
|
||||
staticFrameStack_.clear();
|
||||
ProfileGenerator::staticGcState_ = thread->GetGcState();
|
||||
if (!ProfileGenerator::staticGcState_) {
|
||||
JSTaggedType *sp_ = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
|
||||
InterpretedFrameHandler frameHandler(sp_);
|
||||
for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) {
|
||||
if (frameHandler.IsBreakFrame()) {
|
||||
continue;
|
||||
}
|
||||
auto *method = frameHandler.GetMethod();
|
||||
if (method != nullptr && staticStackInfo_.count(method) == 0) {
|
||||
ParseMethodInfo(method, thread, frameHandler);
|
||||
}
|
||||
staticFrameStack_.push_back(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpuProfiler::ParseMethodInfo(JSMethod *method, JSThread *thread, InterpretedFrameHandler frameHandler)
|
||||
{
|
||||
struct StackInfo codeEntry;
|
||||
auto ecmaVm = thread->GetEcmaVM();
|
||||
if (method != nullptr && method->IsNative()) {
|
||||
codeEntry.codeType = "other";
|
||||
codeEntry.functionName = "native";
|
||||
staticStackInfo_.insert(std::make_pair(method, codeEntry));
|
||||
} else {
|
||||
codeEntry.codeType = "JS";
|
||||
const CString &functionName = method->ParseFunctionName();
|
||||
if (functionName.empty()) {
|
||||
codeEntry.functionName = "anonymous";
|
||||
} else {
|
||||
codeEntry.functionName = functionName.c_str();
|
||||
}
|
||||
// source file
|
||||
tooling::ecmascript::PtJSExtractor *debugExtractor = ecmaVm->GetDebugInfoExtractor(method->GetPandaFile());
|
||||
if (method == nullptr) {
|
||||
return;
|
||||
}
|
||||
const CString &sourceFile = debugExtractor->GetSourceFile(method->GetFileId());
|
||||
if (sourceFile.empty()) {
|
||||
codeEntry.url = "";
|
||||
} else {
|
||||
codeEntry.url = sourceFile.c_str();
|
||||
auto iter = scriptIdMap_.find(codeEntry.url);
|
||||
if (iter == scriptIdMap_.end()) {
|
||||
scriptIdMap_.insert(std::make_pair(codeEntry.url, scriptIdMap_.size() + 1));
|
||||
codeEntry.scriptId = scriptIdMap_.size();
|
||||
} else {
|
||||
codeEntry.scriptId = iter->second;
|
||||
}
|
||||
}
|
||||
// line number
|
||||
int lineNumber = 0;
|
||||
auto lineFunc = [&lineNumber](int line) -> bool {
|
||||
lineNumber = line + 1;
|
||||
return true;
|
||||
};
|
||||
if (!debugExtractor->MatchWithOffset(lineFunc, method->GetFileId(), frameHandler.GetBytecodeOffset())) {
|
||||
codeEntry.lineNumber = 0;
|
||||
} else {
|
||||
codeEntry.lineNumber = lineNumber;
|
||||
}
|
||||
staticStackInfo_.insert(std::make_pair(method, codeEntry));
|
||||
}
|
||||
}
|
||||
|
||||
void CpuProfiler::IsNeedAndGetStack(JSThread *thread)
|
||||
{
|
||||
if (thread->GetStackSignal()) {
|
||||
GetFrameStack(thread);
|
||||
if (sem_post(&CpuProfiler::sem_) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sem_ post failed";
|
||||
return;
|
||||
}
|
||||
thread->SetGetStackSignal(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuProfiler::GetStackSignalHandler(int signal)
|
||||
{
|
||||
JSThread *thread = ProfileProcessor::GetJSThread();
|
||||
GetFrameStack(thread);
|
||||
if (sem_post(&CpuProfiler::sem_) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sem_ post failed";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string CpuProfiler::GetProfileName() const
|
||||
{
|
||||
char time1[16] = {0}; // 16:Time format length
|
||||
char time2[16] = {0}; // 16:Time format length
|
||||
time_t timep = std::time(NULL);
|
||||
struct tm nowTime1;
|
||||
localtime_r(&timep, &nowTime1);
|
||||
size_t result = 0;
|
||||
result = strftime(time1, sizeof(time1), "%Y%m%d", &nowTime1);
|
||||
if (result == 0) {
|
||||
LOG(ERROR, RUNTIME) << "get time failed";
|
||||
return "";
|
||||
}
|
||||
result = strftime(time2, sizeof(time2), "%H%M%S", &nowTime1);
|
||||
if (result == 0) {
|
||||
LOG(ERROR, RUNTIME) << "get time failed";
|
||||
return "";
|
||||
}
|
||||
std::string profileName = "cpuprofile-";
|
||||
profileName += time1;
|
||||
profileName += "TO";
|
||||
profileName += time2;
|
||||
profileName += ".json";
|
||||
return profileName;
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_CPU_PROFILER_H
|
||||
#define ECMASCRIPT_CPU_PROFILER_H
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
#include "ecmascript/cpu_profiler/profile_generator.h"
|
||||
#include "ecmascript/cpu_profiler/profile_processor.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
struct CurrentProcessInfo {
|
||||
time_t nowTimeStamp = 0;
|
||||
time_t tts = 0;
|
||||
pid_t pid = 0;
|
||||
pthread_t tid = 0;
|
||||
};
|
||||
|
||||
class GcStateScope {
|
||||
public:
|
||||
inline explicit GcStateScope(JSThread *thread)
|
||||
{
|
||||
thread_ = thread;
|
||||
thread_->SetGcState(true);
|
||||
}
|
||||
|
||||
inline ~GcStateScope()
|
||||
{
|
||||
thread_->SetGcState(false);
|
||||
}
|
||||
private:
|
||||
JSThread *thread_ = nullptr;
|
||||
};
|
||||
|
||||
class CpuProfiler {
|
||||
public:
|
||||
static CpuProfiler *GetInstance();
|
||||
static void ParseMethodInfo(JSMethod *method, JSThread *thread, InterpretedFrameHandler frameHandler);
|
||||
static void GetFrameStack(JSThread *thread);
|
||||
static void IsNeedAndGetStack(JSThread *thread);
|
||||
static void GetStackSignalHandler(int signal);
|
||||
|
||||
static CMap<JSMethod *, struct StackInfo> staticStackInfo_;
|
||||
static sem_t sem_;
|
||||
static CVector<JSMethod *> staticFrameStack_;
|
||||
|
||||
void StartCpuProfiler(const EcmaVM *vm);
|
||||
void StopCpuProfiler();
|
||||
std::string GetProfileName() const;
|
||||
virtual ~CpuProfiler();
|
||||
private:
|
||||
static CMap<std::string, int> scriptIdMap_;
|
||||
static CpuProfiler *singleton_;
|
||||
|
||||
explicit CpuProfiler();
|
||||
void SetProfileStart(time_t nowTimeStamp);
|
||||
void GetCurrentProcessInfo(struct CurrentProcessInfo ¤tProcessInfo) const;
|
||||
|
||||
bool isOnly_ = false;
|
||||
int interval_ = 500; // 500:Sampling interval 500 microseconds
|
||||
ProfileGenerator *generator_ = nullptr;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_CPU_PROFILE_H
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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/cpu_profiler/profile_generator.h"
|
||||
|
||||
#include <climits>
|
||||
#include "ecmascript/cpu_profiler/cpu_profiler.h"
|
||||
#include "ecmascript/interpreter/interpreter.h"
|
||||
namespace panda::ecmascript {
|
||||
int ProfileGenerator::staticGcState_ = false;
|
||||
ProfileGenerator::ProfileGenerator()
|
||||
{
|
||||
stackTopLines_.push_back(0);
|
||||
}
|
||||
ProfileGenerator::~ProfileGenerator() {}
|
||||
void ProfileGenerator::AddSample(CVector<JSMethod *> sample, time_t sampleTimeStamp)
|
||||
{
|
||||
static int PreviousId = 0;
|
||||
struct MethodKey methodkey;
|
||||
struct MethodNode methodNode;
|
||||
if (staticGcState_) {
|
||||
methodkey.method = reinterpret_cast<JSMethod*>(INT_MAX);
|
||||
methodNode.parentId = methodkey.parentId = PreviousId;
|
||||
auto result = methodMap_.find(methodkey);
|
||||
if (result == methodMap_.end()) {
|
||||
methodNode.id = methodMap_.size() + 1;
|
||||
methodMap_.insert(std::make_pair(methodkey, methodNode.id));
|
||||
methodNode.codeEntry = GetGcInfo();
|
||||
stackTopLines_.push_back(0);
|
||||
methodNodes_.push_back(methodNode);
|
||||
} else {
|
||||
methodNode.id = result->second;
|
||||
}
|
||||
staticGcState_ = false;
|
||||
} else {
|
||||
for (auto method = sample.rbegin(); method != sample.rend(); method++) {
|
||||
methodkey.method = *method;
|
||||
if (method == sample.rbegin()) {
|
||||
methodNode.parentId = methodkey.parentId = 0;
|
||||
} else {
|
||||
methodNode.parentId = methodkey.parentId = methodNode.id;
|
||||
}
|
||||
auto result = methodMap_.find(methodkey);
|
||||
if (result == methodMap_.end()) {
|
||||
int id = methodMap_.size() + 1;
|
||||
methodMap_.insert(std::make_pair(methodkey, id));
|
||||
PreviousId = methodNode.id = id;
|
||||
methodNode.codeEntry = GetMethodInfo(methodkey.method);
|
||||
stackTopLines_.push_back(methodNode.codeEntry.lineNumber);
|
||||
methodNodes_.push_back(methodNode);
|
||||
} else {
|
||||
PreviousId = methodNode.id = result->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
static time_t threadStartTime = 0;
|
||||
struct SampleInfo sampleInfo;
|
||||
sampleInfo.id = methodNode.id;
|
||||
sampleInfo.line = stackTopLines_[methodNode.id];
|
||||
if (threadStartTime == 0) {
|
||||
sampleInfo.timeStamp = sampleTimeStamp - threadStartTime_;
|
||||
} else {
|
||||
sampleInfo.timeStamp = sampleTimeStamp - threadStartTime;
|
||||
}
|
||||
samples_.push_back(sampleInfo);
|
||||
threadStartTime = sampleTimeStamp;
|
||||
}
|
||||
|
||||
void ProfileGenerator::WriteAddNodes()
|
||||
{
|
||||
sampleData_ += "{\"args\":{\"data\":{\"cpuProfile\":{\"nodes\":[";
|
||||
for (auto it : methodNodes_) {
|
||||
sampleData_ += "{\"callFrame\":{\"codeType\":\"" + it.codeEntry.codeType + "\",";
|
||||
if (it.parentId == 0) {
|
||||
sampleData_ += "\"functionName\":\"(root)\",\"scriptId\":0},\"id\":1},";
|
||||
continue;
|
||||
}
|
||||
if (it.codeEntry.codeType == "other" || it.codeEntry.codeType == "jsvm") {
|
||||
sampleData_ += "\"functionName\":\"" + it.codeEntry.functionName + "\",\"scriptId\":" +
|
||||
std::to_string(it.codeEntry.scriptId) + "},\"id\":" + std::to_string(it.id);
|
||||
} else {
|
||||
sampleData_ += "\"columnNumber\":" + std::to_string(it.codeEntry.columnNumber) +
|
||||
",\"functionName\":\"" + it.codeEntry.functionName + "\",\"lineNumber\":\"" +
|
||||
std::to_string(it.codeEntry.lineNumber) + "\",\"scriptId\":" +
|
||||
std::to_string(it.codeEntry.scriptId) + ",\"url\":\"" + it.codeEntry.url +
|
||||
"\"},\"id\":" + std::to_string(it.id);
|
||||
}
|
||||
sampleData_ += ",\"parent\":" + std::to_string(it.parentId) + "},";
|
||||
}
|
||||
sampleData_.pop_back();
|
||||
sampleData_ += "],\"samples\":[";
|
||||
}
|
||||
|
||||
void ProfileGenerator::WriteAddSamples()
|
||||
{
|
||||
if (samples_.empty()) {
|
||||
return;
|
||||
}
|
||||
std::string sampleId = "";
|
||||
std::string sampleLine = "";
|
||||
std::string timeStamp = "";
|
||||
for (auto it : samples_) {
|
||||
sampleId += std::to_string(it.id) + ",";
|
||||
sampleLine += std::to_string(it.line) + ",";
|
||||
timeStamp += std::to_string(it.timeStamp) + ",";
|
||||
}
|
||||
sampleId.pop_back();
|
||||
sampleLine.pop_back();
|
||||
timeStamp.pop_back();
|
||||
sampleData_ += sampleId + "]},\"lines\":[" + sampleLine + "],\"timeDeltas\":[" + timeStamp + "]}},";
|
||||
}
|
||||
|
||||
void ProfileGenerator::WriteMethodsAndSampleInfo(bool timeEnd)
|
||||
{
|
||||
if (methodNodes_.size() >= 10) { // 10:Number of nodes currently stored
|
||||
WriteAddNodes();
|
||||
WriteAddSamples();
|
||||
methodNodes_.clear();
|
||||
samples_.clear();
|
||||
} else if (samples_.size() == 100 || timeEnd) { // 100:Number of samples currently stored
|
||||
if (!methodNodes_.empty()) {
|
||||
WriteAddNodes();
|
||||
WriteAddSamples();
|
||||
methodNodes_.clear();
|
||||
samples_.clear();
|
||||
} else if (!samples_.empty()) {
|
||||
sampleData_ += "{\"args\":{\"data\":{\"cpuProfile\":{\"samples\":[";
|
||||
WriteAddSamples();
|
||||
samples_.clear();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
sampleData_ += "\"cat\":\"disabled-by-default-v8.cpu_profiler\",\"id\":"
|
||||
"\"0x2\",\"name\":\"ProfileChunk\",\"ph\":\"P\",\"pid\":";
|
||||
pid_t pid = getpid();
|
||||
pthread_t tid = syscall(SYS_gettid);
|
||||
time_t ts = ProfileProcessor::GetMicrosecondsTimeStamp();
|
||||
ts = ts % TIME_CHANGE;
|
||||
struct timespec time = {0, 0};
|
||||
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||
time_t tts = time.tv_nsec / 1000; // 1000:Nanoseconds to milliseconds.
|
||||
sampleData_ += std::to_string(pid) + ",\"tid\":" +
|
||||
std::to_string(tid) + ",\"ts\":" +
|
||||
std::to_string(ts) + ",\"tts\":" +
|
||||
std::to_string(tts) + "},\n";
|
||||
}
|
||||
|
||||
CVector<struct MethodNode> ProfileGenerator::GetMethodNodes() const
|
||||
{
|
||||
return methodNodes_;
|
||||
}
|
||||
|
||||
CDeque<struct SampleInfo> ProfileGenerator::GetSamples() const
|
||||
{
|
||||
return samples_;
|
||||
}
|
||||
|
||||
std::string ProfileGenerator::GetSampleData() const
|
||||
{
|
||||
return sampleData_;
|
||||
}
|
||||
|
||||
struct StackInfo ProfileGenerator::GetMethodInfo(JSMethod *method)
|
||||
{
|
||||
struct StackInfo entry;
|
||||
auto iter = CpuProfiler::staticStackInfo_.find(method);
|
||||
if (iter != CpuProfiler::staticStackInfo_.end()) {
|
||||
entry = iter->second;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
struct StackInfo ProfileGenerator::GetGcInfo()
|
||||
{
|
||||
struct StackInfo gcEntry;
|
||||
gcEntry.codeType = "jsvm";
|
||||
gcEntry.functionName = "garbage collector";
|
||||
return gcEntry;
|
||||
}
|
||||
|
||||
void ProfileGenerator::SetThreadStartTime(time_t threadStartTime)
|
||||
{
|
||||
threadStartTime_ = threadStartTime;
|
||||
}
|
||||
|
||||
void ProfileGenerator::SetStartsampleData(std::string sampleData)
|
||||
{
|
||||
sampleData_ += sampleData;
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_PROFILE_GENERSTOR_H
|
||||
#define ECMASCRIPT_PROFILE_GENERSTOR_H
|
||||
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include "ecmascript/js_method.h"
|
||||
#include "ecmascript/mem/c_containers.h"
|
||||
namespace panda::ecmascript {
|
||||
const long long TIME_CHANGE = 10000000000000; // 10000000000000:Discard the first 3 bits of the current nanosecond time
|
||||
struct StackInfo {
|
||||
std::string codeType = "";
|
||||
std::string functionName = "";
|
||||
int columnNumber = 0;
|
||||
int lineNumber = 0;
|
||||
int scriptId = 0;
|
||||
std::string url = "";
|
||||
};
|
||||
struct MethodNode {
|
||||
int id = 0;
|
||||
int parentId = 0;
|
||||
struct StackInfo codeEntry;
|
||||
};
|
||||
struct SampleInfo {
|
||||
int id = 0;
|
||||
int line = 0;
|
||||
time_t timeStamp = 0;
|
||||
};
|
||||
struct MethodKey {
|
||||
JSMethod *method = nullptr;
|
||||
int parentId = 0;
|
||||
bool operator< (const MethodKey &methodKey) const
|
||||
{
|
||||
return parentId < methodKey.parentId || (parentId == methodKey.parentId && method < methodKey.method);
|
||||
}
|
||||
};
|
||||
|
||||
class ProfileGenerator {
|
||||
public:
|
||||
explicit ProfileGenerator();
|
||||
virtual ~ProfileGenerator();
|
||||
|
||||
void AddSample(CVector<JSMethod *> sample, time_t sampleTimeStamp);
|
||||
void WriteMethodsAndSampleInfo(bool timeEnd);
|
||||
CVector<struct MethodNode> GetMethodNodes() const;
|
||||
CDeque<struct SampleInfo> GetSamples() const;
|
||||
std::string GetSampleData() const;
|
||||
void SetThreadStartTime(time_t threadStartTime);
|
||||
void SetStartsampleData(std::string sampleData);
|
||||
|
||||
static int staticGcState_;
|
||||
private:
|
||||
void WriteAddNodes();
|
||||
void WriteAddSamples();
|
||||
struct StackInfo GetMethodInfo(JSMethod *method);
|
||||
struct StackInfo GetGcInfo();
|
||||
|
||||
CVector<struct MethodNode> methodNodes_;
|
||||
CVector<int> stackTopLines_;
|
||||
CMap<struct MethodKey, int> methodMap_;
|
||||
CDeque<struct SampleInfo> samples_;
|
||||
std::string sampleData_;
|
||||
time_t threadStartTime_;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_PROFILE_GENERSTOR_H
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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/cpu_profiler/profile_processor.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <sys/time.h>
|
||||
#include "ecmascript/cpu_profiler/cpu_profiler.h"
|
||||
#include "ecmascript/interpreter/interpreter.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
JSThread *ProfileProcessor::thread_ = nullptr;
|
||||
bool ProfileProcessor::isStart_ = true;
|
||||
ProfileProcessor::ProfileProcessor(ProfileGenerator *generator, const EcmaVM *vm, int interval)
|
||||
{
|
||||
generator_ = generator;
|
||||
interval_ = interval;
|
||||
pid_ = pthread_self();
|
||||
thread_ = vm->GetAssociatedJSThread();
|
||||
}
|
||||
ProfileProcessor::~ProfileProcessor() {}
|
||||
|
||||
bool ProfileProcessor::Run(uint32_t threadIndex)
|
||||
{
|
||||
time_t startTime = 0;
|
||||
time_t endTime = 0;
|
||||
startTime = GetMicrosecondsTimeStamp();
|
||||
generator_->SetThreadStartTime(startTime);
|
||||
while (isStart_) {
|
||||
#if ECMASCRIPT_ENABLE_ACTIVE_CPUPROFILER
|
||||
JSThread *thread = GetJSThread();
|
||||
ProfileGenerator::staticGcState_ = thread->GetGcState();
|
||||
if (!ProfileGenerator::staticGcState_) {
|
||||
thread->SetGetStackSignal(true);
|
||||
if (sem_wait(&CpuProfiler::sem_) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sem_ wait failed";
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (pthread_kill(pid_, SIGINT) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "pthread_kill signal failed";
|
||||
return false;
|
||||
}
|
||||
if (sem_wait(&CpuProfiler::sem_) != 0) {
|
||||
LOG(ERROR, RUNTIME) << "sem_ wait failed";
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
endTime = GetMicrosecondsTimeStamp();
|
||||
generator_->AddSample(CpuProfiler::staticFrameStack_, endTime);
|
||||
if (generator_->GetMethodNodes().size() >= 10 || // 10:Number of nodes currently stored
|
||||
generator_->GetSamples().size() == 100) { // 100:Number of Samples currently stored
|
||||
generator_->WriteMethodsAndSampleInfo(false);
|
||||
}
|
||||
time_t ts = interval_ - (endTime - startTime);
|
||||
if (ts > 0) {
|
||||
usleep(ts);
|
||||
}
|
||||
startTime = GetMicrosecondsTimeStamp();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t ProfileProcessor::GetMicrosecondsTimeStamp()
|
||||
{
|
||||
struct timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
return (time.tv_sec * 1000000 + time.tv_usec); // 1000000:Second to subtle
|
||||
}
|
||||
|
||||
JSThread *ProfileProcessor::GetJSThread()
|
||||
{
|
||||
return thread_;
|
||||
}
|
||||
|
||||
void ProfileProcessor::SetIsStart(bool isStart)
|
||||
{
|
||||
isStart_ = isStart;
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_CPU_PROCESSOR_H
|
||||
#define ECMASCRIPT_CPU_PROCESSOR_H
|
||||
#include <pthread.h>
|
||||
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/cpu_profiler/profile_generator.h"
|
||||
#include "ecmascript/interpreter/frame_handler.h"
|
||||
#include "ecmascript/platform/task.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
class ProfileProcessor : public Task {
|
||||
public:
|
||||
static time_t GetMicrosecondsTimeStamp();
|
||||
static JSThread *GetJSThread();
|
||||
static void SetIsStart(bool isStart);
|
||||
|
||||
explicit ProfileProcessor(ProfileGenerator *generator, const EcmaVM *vm, int interval);
|
||||
virtual ~ProfileProcessor();
|
||||
|
||||
bool Run(uint32_t threadIndex) override;
|
||||
|
||||
NO_COPY_SEMANTIC(ProfileProcessor);
|
||||
NO_MOVE_SEMANTIC(ProfileProcessor);
|
||||
private:
|
||||
static JSThread *thread_;
|
||||
static bool isStart_;
|
||||
ProfileGenerator *generator_ = nullptr;
|
||||
int interval_ = 0;
|
||||
pthread_t pid_ = 0;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_CPU_PROCESSOR_H
|
||||
+174
-171
@@ -25,8 +25,8 @@
|
||||
#include "ecmascript/global_dictionary-inl.h"
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/ic/ic_handler.h"
|
||||
#include "ecmascript/ic/proto_change_details.h"
|
||||
#include "ecmascript/ic/property_box.h"
|
||||
#include "ecmascript/ic/proto_change_details.h"
|
||||
#include "ecmascript/interpreter/frame_handler.h"
|
||||
#include "ecmascript/jobs/micro_job_queue.h"
|
||||
#include "ecmascript/jobs/pending_job.h"
|
||||
@@ -302,7 +302,7 @@ static void DumpHClass(JSThread *thread, const JSHClass *jshclass, std::ostream
|
||||
jshclass->GetPrototype().DumpTaggedValue(thread, os);
|
||||
os << "\n";
|
||||
os << " - PropertyDescriptors :" << std::setw(DUMP_TYPE_OFFSET);
|
||||
JSTaggedValue attrs = jshclass->GetAttributes();
|
||||
JSTaggedValue attrs = jshclass->GetLayout();
|
||||
attrs.DumpTaggedValue(thread, os);
|
||||
os << "\n";
|
||||
if (withDetail && !attrs.IsNull()) {
|
||||
@@ -325,8 +325,8 @@ static void DumpHClass(JSThread *thread, const JSHClass *jshclass, std::ostream
|
||||
os << "| Callable :" << jshclass->IsCallable();
|
||||
os << "| Extensible :" << jshclass->IsExtensible();
|
||||
os << "| ElementRepresentation :" << static_cast<int>(jshclass->GetElementRepresentation());
|
||||
os << "| UnusedInlineProperties :" << std::dec << jshclass->GetUnusedInlinedProps();
|
||||
os << "| UnusedOutProperties :" << std::dec << jshclass->GetUnusedNonInlinedProps();
|
||||
os << "| NumberOfProps :" << std::dec << jshclass->NumberOfProps();
|
||||
os << "| InlinedProperties :" << std::dec << jshclass->GetInlinedProperties();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
@@ -485,7 +485,7 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os)
|
||||
JSPromiseExecutorFunction::Cast(obj)->Dump(thread, os);
|
||||
break;
|
||||
case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION:
|
||||
JSPromiseAllResolveElementFunction::Cast(obj)->Dump(thread);
|
||||
JSPromiseAllResolveElementFunction::Cast(obj)->Dump(thread, os);
|
||||
break;
|
||||
case JSType::MICRO_JOB_QUEUE:
|
||||
MicroJobQueue::Cast(obj)->Dump(thread, os);
|
||||
@@ -672,18 +672,21 @@ void JSTaggedValue::Dump(JSThread *thread, std::ostream &os) const
|
||||
|
||||
if (IsHeapObject()) {
|
||||
TaggedObject *obj = GetTaggedObject();
|
||||
if (thread == nullptr) {
|
||||
thread = obj->GetJSThread();
|
||||
}
|
||||
DumpObject(thread, obj, os);
|
||||
}
|
||||
}
|
||||
|
||||
void JSTaggedValue::Dump(JSThread *thread) const
|
||||
void JSTaggedValue::D() const
|
||||
{
|
||||
Dump(thread, std::cout);
|
||||
Dump(nullptr, std::cout);
|
||||
}
|
||||
|
||||
void JSTaggedValue::DumpVal(JSThread *thread, JSTaggedType val)
|
||||
void JSTaggedValue::DV(JSTaggedType val)
|
||||
{
|
||||
JSTaggedValue(val).Dump(thread);
|
||||
JSTaggedValue(val).D();
|
||||
}
|
||||
|
||||
void JSThread::DumpStack()
|
||||
@@ -844,13 +847,13 @@ void JSObject::Dump(JSThread *thread, std::ostream &os) const
|
||||
}
|
||||
|
||||
if (!properties->IsDictionaryMode()) {
|
||||
JSTaggedValue attrs = jshclass->GetAttributes();
|
||||
JSTaggedValue attrs = jshclass->GetLayout();
|
||||
if (attrs.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetTaggedObject());
|
||||
int propNumber = jshclass->GetPropertiesNumber();
|
||||
int propNumber = jshclass->NumberOfProps();
|
||||
os << " <LayoutInfo[" << std::dec << propNumber << "]>\n";
|
||||
for (int i = 0; i < propNumber; i++) {
|
||||
JSTaggedValue key = layoutInfo->GetKey(i);
|
||||
@@ -863,7 +866,7 @@ void JSObject::Dump(JSThread *thread, std::ostream &os) const
|
||||
if (attr.IsInlinedProps()) {
|
||||
val = GetPropertyInlinedProps(i);
|
||||
} else {
|
||||
val = properties->Get(i - JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS);
|
||||
val = properties->Get(i - jshclass->GetInlinedProperties());
|
||||
}
|
||||
val.DumpTaggedValue(thread, os);
|
||||
os << ") ";
|
||||
@@ -898,13 +901,13 @@ void AccessorData::Dump(JSThread *thread, std::ostream &os) const
|
||||
void Program::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Location: ";
|
||||
GetLocation().Dump(thread);
|
||||
GetLocation().D();
|
||||
os << "\n";
|
||||
os << " - ConstantPool: ";
|
||||
GetConstantPool().Dump(thread);
|
||||
GetConstantPool().D();
|
||||
os << "\n";
|
||||
os << " - MainFunction: ";
|
||||
GetMainFunction().Dump(thread);
|
||||
GetMainFunction().D();
|
||||
os << "\n";
|
||||
os << " - MethodsData: " << GetMethodsData() << "\n";
|
||||
os << " - NumberMethods: " << GetNumberMethods() << "\n";
|
||||
@@ -918,25 +921,25 @@ void ConstantPool::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - ProtoOrDynClass: ";
|
||||
GetProtoOrDynClass().Dump(thread);
|
||||
GetProtoOrDynClass().D();
|
||||
os << "\n";
|
||||
os << " - LexicalEnv: ";
|
||||
GetLexicalEnv().Dump(thread);
|
||||
GetLexicalEnv().D();
|
||||
os << "\n";
|
||||
os << " - HomeObject: ";
|
||||
GetHomeObject().Dump(thread);
|
||||
GetHomeObject().D();
|
||||
os << "\n";
|
||||
os << " - FunctionInfoFlag: ";
|
||||
GetFunctionInfoFlag().Dump(thread);
|
||||
GetFunctionInfoFlag().D();
|
||||
os << "\n";
|
||||
os << " - FunctionExtraInfo: ";
|
||||
GetFunctionExtraInfo().Dump(thread);
|
||||
GetFunctionExtraInfo().D();
|
||||
os << "\n";
|
||||
os << " - ConstantPool: ";
|
||||
GetConstantPool().Dump(thread);
|
||||
GetConstantPool().D();
|
||||
os << "\n";
|
||||
os << " - ProfileTypeInfo: ";
|
||||
GetProfileTypeInfo().Dump(thread);
|
||||
GetProfileTypeInfo().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1098,34 +1101,34 @@ void JSStringIterator::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSTypedArray::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - viewed-array-buffer: ";
|
||||
GetViewedArrayBuffer().Dump(thread);
|
||||
GetViewedArrayBuffer().D();
|
||||
os << " - typed-array-name: ";
|
||||
GetTypedArrayName().Dump(thread);
|
||||
GetTypedArrayName().D();
|
||||
os << " - byte-length: ";
|
||||
GetByteLength().Dump(thread);
|
||||
GetByteLength().D();
|
||||
os << " - byte-offset: ";
|
||||
GetByteOffset().Dump(thread);
|
||||
GetByteOffset().D();
|
||||
os << " - array-length: ";
|
||||
GetArrayLength().Dump(thread);
|
||||
GetArrayLength().D();
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
|
||||
void JSRegExp::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - LastIndex: ";
|
||||
GetLastIndex().Dump(thread);
|
||||
GetLastIndex().D();
|
||||
os << "\n";
|
||||
os << " - ByteCodeBuffer: ";
|
||||
GetByteCodeBuffer().Dump(thread);
|
||||
GetByteCodeBuffer().D();
|
||||
os << "\n";
|
||||
os << " - OriginalSource: ";
|
||||
GetOriginalSource().Dump(thread);
|
||||
GetOriginalSource().D();
|
||||
os << "\n";
|
||||
os << " - OriginalFlags: ";
|
||||
GetOriginalFlags().Dump(thread);
|
||||
GetOriginalFlags().D();
|
||||
os << "\n";
|
||||
os << " - Length: ";
|
||||
GetLength().Dump(thread);
|
||||
GetLength().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1145,13 +1148,13 @@ void JSSymbol::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - hash-field: ";
|
||||
JSTaggedValue hashField = GetHashField();
|
||||
hashField.Dump(thread);
|
||||
hashField.D();
|
||||
os << " - flags: ";
|
||||
JSTaggedValue flags = GetFlags();
|
||||
flags.Dump(thread);
|
||||
flags.D();
|
||||
os << " - description: ";
|
||||
JSTaggedValue description = GetDescription();
|
||||
description.Dump(thread);
|
||||
description.D();
|
||||
}
|
||||
|
||||
void LexicalEnv::Dump(JSThread *thread, std::ostream &os) const
|
||||
@@ -1372,142 +1375,142 @@ void GlobalEnv::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSDataView::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - data-view: ";
|
||||
GetDataView().Dump(thread);
|
||||
GetDataView().D();
|
||||
os << " - buffer: ";
|
||||
GetViewedArrayBuffer().Dump(thread);
|
||||
GetViewedArrayBuffer().D();
|
||||
os << " - byte-length: ";
|
||||
GetByteLength().Dump(thread);
|
||||
GetByteLength().D();
|
||||
os << " - byte-offset: ";
|
||||
GetByteOffset().Dump(thread);
|
||||
GetByteOffset().D();
|
||||
}
|
||||
|
||||
void JSArrayBuffer::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - byte-length: ";
|
||||
GetArrayBufferByteLength().Dump(thread);
|
||||
GetArrayBufferByteLength().D();
|
||||
os << " - buffer-data: ";
|
||||
GetArrayBufferData().Dump(thread);
|
||||
GetArrayBufferData().D();
|
||||
os << " - Shared: ";
|
||||
GetShared().Dump(thread);
|
||||
GetShared().D();
|
||||
}
|
||||
|
||||
void PromiseReaction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - promise-capability: ";
|
||||
GetPromiseCapability().Dump(thread);
|
||||
GetPromiseCapability().D();
|
||||
os << " - type: ";
|
||||
GetType().Dump(thread);
|
||||
GetType().D();
|
||||
os << " - handler: ";
|
||||
GetHandler().Dump(thread);
|
||||
GetHandler().D();
|
||||
}
|
||||
|
||||
void PromiseCapability::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - promise: ";
|
||||
GetPromise().Dump(thread);
|
||||
GetPromise().D();
|
||||
os << " - resolve: ";
|
||||
GetResolve().Dump(thread);
|
||||
GetResolve().D();
|
||||
os << " - reject: ";
|
||||
GetReject().Dump(thread);
|
||||
GetReject().D();
|
||||
}
|
||||
|
||||
void PromiseIteratorRecord::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - iterator: ";
|
||||
GetIterator().Dump(thread);
|
||||
GetIterator().D();
|
||||
os << " - done: ";
|
||||
GetDone().Dump(thread);
|
||||
GetDone().D();
|
||||
}
|
||||
|
||||
void PromiseRecord::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - value: ";
|
||||
GetValue().Dump(thread);
|
||||
GetValue().D();
|
||||
}
|
||||
|
||||
void ResolvingFunctionsRecord::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - resolve-function: ";
|
||||
GetResolveFunction().Dump(thread);
|
||||
GetResolveFunction().D();
|
||||
os << " - reject-function: ";
|
||||
GetRejectFunction().Dump(thread);
|
||||
GetRejectFunction().D();
|
||||
}
|
||||
|
||||
void JSPromise::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - promise-state: ";
|
||||
GetPromiseState().Dump(thread);
|
||||
GetPromiseState().D();
|
||||
os << " - promise-result: ";
|
||||
GetPromiseResult().Dump(thread);
|
||||
GetPromiseResult().D();
|
||||
os << " - promise-fulfill-reactions: ";
|
||||
GetPromiseFulfillReactions().Dump(thread);
|
||||
GetPromiseFulfillReactions().D();
|
||||
os << " - promise-reject-reactions: ";
|
||||
GetPromiseRejectReactions().Dump(thread);
|
||||
GetPromiseRejectReactions().D();
|
||||
os << " - promise-is-handled: ";
|
||||
GetPromiseIsHandled().Dump(thread);
|
||||
GetPromiseIsHandled().D();
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
|
||||
void JSPromiseReactionsFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - promise: ";
|
||||
GetPromise().Dump(thread);
|
||||
GetPromise().D();
|
||||
os << " - already-resolved: ";
|
||||
GetAlreadyResolved().Dump(thread);
|
||||
GetAlreadyResolved().D();
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
|
||||
void JSPromiseExecutorFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - capability: ";
|
||||
GetCapability().Dump(thread);
|
||||
GetCapability().D();
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
|
||||
void JSPromiseAllResolveElementFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - index: ";
|
||||
GetIndex().Dump(thread);
|
||||
GetIndex().D();
|
||||
os << " - values: ";
|
||||
GetValues().Dump(thread);
|
||||
GetValues().D();
|
||||
os << " - capability: ";
|
||||
GetCapabilities().Dump(thread);
|
||||
GetCapabilities().D();
|
||||
os << " - remaining-elements: ";
|
||||
GetRemainingElements().Dump(thread);
|
||||
GetRemainingElements().D();
|
||||
os << " - already-called: ";
|
||||
GetAlreadyCalled().Dump(thread);
|
||||
GetAlreadyCalled().D();
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
|
||||
void MicroJobQueue::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - promise-job-queue: ";
|
||||
GetPromiseJobQueue().Dump(thread);
|
||||
GetPromiseJobQueue().D();
|
||||
os << " - script-job-queue: ";
|
||||
GetScriptJobQueue().Dump(thread);
|
||||
GetScriptJobQueue().D();
|
||||
}
|
||||
|
||||
void PendingJob::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - job: ";
|
||||
GetJob().Dump(thread);
|
||||
GetJob().D();
|
||||
os << " - arguments: ";
|
||||
GetArguments().Dump(thread);
|
||||
GetArguments().D();
|
||||
}
|
||||
|
||||
void CompletionRecord::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - type: ";
|
||||
GetType().Dump(thread);
|
||||
GetType().D();
|
||||
os << " - value: ";
|
||||
GetValue().Dump(thread);
|
||||
GetValue().D();
|
||||
}
|
||||
|
||||
void JSProxyRevocFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - RevocableProxy: ";
|
||||
os << "\n";
|
||||
GetRevocableProxy().Dump(thread);
|
||||
GetRevocableProxy().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
@@ -1520,7 +1523,7 @@ void JSAsyncAwaitStatusFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - AsyncContext: ";
|
||||
os << "\n";
|
||||
GetAsyncContext().Dump(thread);
|
||||
GetAsyncContext().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
@@ -1532,13 +1535,13 @@ void JSGeneratorFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSIntlBoundFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - NumberFormat: ";
|
||||
GetNumberFormat().Dump(thread);
|
||||
GetNumberFormat().D();
|
||||
os << "\n";
|
||||
os << " - DateTimeFormat: ";
|
||||
GetDateTimeFormat().Dump(thread);
|
||||
GetDateTimeFormat().D();
|
||||
os << "\n";
|
||||
os << " - Collator: ";
|
||||
GetCollator().Dump(thread);
|
||||
GetCollator().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1546,40 +1549,40 @@ void JSIntlBoundFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
void PropertyBox::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Value: ";
|
||||
GetValue().Dump(thread);
|
||||
GetValue().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void PrototypeHandler::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - HandlerInfo: ";
|
||||
GetHandlerInfo().Dump(thread);
|
||||
GetHandlerInfo().D();
|
||||
os << "\n";
|
||||
os << " - ProtoCell: ";
|
||||
GetHandlerInfo().Dump(thread);
|
||||
GetHandlerInfo().D();
|
||||
os << "\n";
|
||||
os << " - Holder: ";
|
||||
GetHandlerInfo().Dump(thread);
|
||||
GetHandlerInfo().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void TransitionHandler::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - HandlerInfo: ";
|
||||
GetHandlerInfo().Dump(thread);
|
||||
GetHandlerInfo().D();
|
||||
os << "\n";
|
||||
os << " - TransitionHClass: ";
|
||||
GetTransitionHClass().Dump(thread);
|
||||
GetTransitionHClass().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void JSRealm::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Value: ";
|
||||
GetValue().Dump(thread);
|
||||
GetValue().D();
|
||||
os << "\n";
|
||||
os << " - GlobalEnv: ";
|
||||
GetGlobalEnv().Dump(thread);
|
||||
GetGlobalEnv().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1587,7 +1590,7 @@ void JSRealm::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSIntl::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - FallbackSymbol: ";
|
||||
GetFallbackSymbol().Dump(thread);
|
||||
GetFallbackSymbol().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1595,7 +1598,7 @@ void JSIntl::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSLocale::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - IcuField: ";
|
||||
GetIcuField().Dump(thread);
|
||||
GetIcuField().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1603,37 +1606,37 @@ void JSLocale::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSDateTimeFormat::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Locale: ";
|
||||
GetLocale().Dump(thread);
|
||||
GetLocale().D();
|
||||
os << "\n";
|
||||
os << " - Calendar: ";
|
||||
GetCalendar().Dump(thread);
|
||||
GetCalendar().D();
|
||||
os << "\n";
|
||||
os << " - NumberingSystem: ";
|
||||
GetNumberingSystem().Dump(thread);
|
||||
GetNumberingSystem().D();
|
||||
os << "\n";
|
||||
os << " - TimeZone: ";
|
||||
GetTimeZone().Dump(thread);
|
||||
GetTimeZone().D();
|
||||
os << "\n";
|
||||
os << " - HourCycle: ";
|
||||
GetHourCycle().Dump(thread);
|
||||
GetHourCycle().D();
|
||||
os << "\n";
|
||||
os << " - LocaleIcu: ";
|
||||
GetLocaleIcu().Dump(thread);
|
||||
GetLocaleIcu().D();
|
||||
os << "\n";
|
||||
os << " - SimpleDateTimeFormatIcu: ";
|
||||
GetSimpleDateTimeFormatIcu().Dump(thread);
|
||||
GetSimpleDateTimeFormatIcu().D();
|
||||
os << "\n";
|
||||
os << " - Iso8601: ";
|
||||
GetIso8601().Dump(thread);
|
||||
GetIso8601().D();
|
||||
os << "\n";
|
||||
os << " - DateStyle: ";
|
||||
GetDateStyle().Dump(thread);
|
||||
GetDateStyle().D();
|
||||
os << "\n";
|
||||
os << " - TimeStyle: ";
|
||||
GetTimeStyle().Dump(thread);
|
||||
GetTimeStyle().D();
|
||||
os << "\n";
|
||||
os << " - BoundFormat: ";
|
||||
GetBoundFormat().Dump(thread);
|
||||
GetBoundFormat().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1641,25 +1644,25 @@ void JSDateTimeFormat::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSRelativeTimeFormat::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Locale: ";
|
||||
GetLocale().Dump(thread);
|
||||
GetLocale().D();
|
||||
os << "\n";
|
||||
os << " - InitializedRelativeTimeFormat: ";
|
||||
GetInitializedRelativeTimeFormat().Dump(thread);
|
||||
GetInitializedRelativeTimeFormat().D();
|
||||
os << "\n";
|
||||
os << " - NumberingSystem: ";
|
||||
GetNumberingSystem().Dump(thread);
|
||||
GetNumberingSystem().D();
|
||||
os << "\n";
|
||||
os << " - Style: ";
|
||||
GetStyle().Dump(thread);
|
||||
GetStyle().D();
|
||||
os << "\n";
|
||||
os << " - Numeric: ";
|
||||
GetNumeric().Dump(thread);
|
||||
GetNumeric().D();
|
||||
os << "\n";
|
||||
os << " - AvailableLocales: ";
|
||||
GetAvailableLocales().Dump(thread);
|
||||
GetAvailableLocales().D();
|
||||
os << "\n";
|
||||
os << " - IcuField: ";
|
||||
GetIcuField().Dump(thread);
|
||||
GetIcuField().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1667,45 +1670,45 @@ void JSRelativeTimeFormat::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSNumberFormat::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Locale: ";
|
||||
GetLocale().Dump(thread);
|
||||
GetLocale().D();
|
||||
os << "\n" << " - NumberingSystem: ";
|
||||
GetNumberingSystem().Dump(thread);
|
||||
GetNumberingSystem().D();
|
||||
os << "\n" << " - Style: ";
|
||||
GetStyle().Dump(thread);
|
||||
GetStyle().D();
|
||||
os << "\n" << " - Currency: ";
|
||||
GetCurrency().Dump(thread);
|
||||
GetCurrency().D();
|
||||
os << "\n" << " - CurrencyDisplay: ";
|
||||
GetCurrencyDisplay().Dump(thread);
|
||||
GetCurrencyDisplay().D();
|
||||
os << "\n" << " - CurrencySign: ";
|
||||
GetCurrencySign().Dump(thread);
|
||||
GetCurrencySign().D();
|
||||
os << "\n" << " - Unit: ";
|
||||
GetUnit().Dump(thread);
|
||||
GetUnit().D();
|
||||
os << "\n" << " - UnitDisplay: ";
|
||||
GetUnitDisplay().Dump(thread);
|
||||
GetUnitDisplay().D();
|
||||
os << "\n" << " - MinimumIntegerDigits: ";
|
||||
GetMinimumIntegerDigits().Dump(thread);
|
||||
GetMinimumIntegerDigits().D();
|
||||
os << "\n" << " - MinimumFractionDigits: ";
|
||||
GetMinimumFractionDigits().Dump(thread);
|
||||
GetMinimumFractionDigits().D();
|
||||
os << "\n" << " - MaximumFractionDigits: ";
|
||||
GetMaximumFractionDigits().Dump(thread);
|
||||
GetMaximumFractionDigits().D();
|
||||
os << "\n" << " - MinimumSignificantDigits: ";
|
||||
GetMinimumSignificantDigits().Dump(thread);
|
||||
GetMinimumSignificantDigits().D();
|
||||
os << "\n" << " - MaximumSignificantDigits: ";
|
||||
GetMaximumSignificantDigits().Dump(thread);
|
||||
GetMaximumSignificantDigits().D();
|
||||
os << "\n" << " - UseGrouping: ";
|
||||
GetUseGrouping().Dump(thread);
|
||||
GetUseGrouping().D();
|
||||
os << "\n" << " - RoundingType: ";
|
||||
GetUseGrouping().Dump(thread);
|
||||
GetUseGrouping().D();
|
||||
os << "\n" << " - Notation: ";
|
||||
GetMinimumIntegerDigits().Dump(thread);
|
||||
GetMinimumIntegerDigits().D();
|
||||
os << "\n" << " - CompactDisplay: ";
|
||||
GetMaximumSignificantDigits().Dump(thread);
|
||||
GetMaximumSignificantDigits().D();
|
||||
os << "\n" << " - SignDisplay: ";
|
||||
GetMinimumFractionDigits().Dump(thread);
|
||||
GetMinimumFractionDigits().D();
|
||||
os << "\n" << " - BoundFormat: ";
|
||||
GetMaximumFractionDigits().Dump(thread);
|
||||
GetMaximumFractionDigits().D();
|
||||
os << "\n" << " - IcuField: ";
|
||||
GetMinimumSignificantDigits().Dump(thread);
|
||||
GetMinimumSignificantDigits().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1713,31 +1716,31 @@ void JSNumberFormat::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSCollator::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - IcuField: ";
|
||||
GetIcuField().Dump(thread);
|
||||
GetIcuField().D();
|
||||
os << "\n";
|
||||
os << " - Locale: ";
|
||||
GetLocale().Dump(thread);
|
||||
GetLocale().D();
|
||||
os << "\n";
|
||||
os << " - Usage: ";
|
||||
GetUsage().Dump(thread);
|
||||
GetUsage().D();
|
||||
os << "\n";
|
||||
os << " - Sensitivity: ";
|
||||
GetSensitivity().Dump(thread);
|
||||
GetSensitivity().D();
|
||||
os << "\n";
|
||||
os << " - IgnorePunctuation: ";
|
||||
GetIgnorePunctuation().Dump(thread);
|
||||
GetIgnorePunctuation().D();
|
||||
os << "\n";
|
||||
os << " - Collation: ";
|
||||
GetCollation().Dump(thread);
|
||||
GetCollation().D();
|
||||
os << "\n";
|
||||
os << " - Numeric: ";
|
||||
GetNumeric().Dump(thread);
|
||||
GetNumeric().D();
|
||||
os << "\n";
|
||||
os << " - CaseFirst: ";
|
||||
GetCaseFirst().Dump(thread);
|
||||
GetCaseFirst().D();
|
||||
os << "\n";
|
||||
os << " - BoundCompare: ";
|
||||
GetBoundCompare().Dump(thread);
|
||||
GetBoundCompare().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1745,37 +1748,37 @@ void JSCollator::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSPluralRules::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Locale: ";
|
||||
GetLocale().Dump(thread);
|
||||
GetLocale().D();
|
||||
os << "\n";
|
||||
os << " - InitializedPluralRules: ";
|
||||
GetInitializedPluralRules().Dump(thread);
|
||||
GetInitializedPluralRules().D();
|
||||
os << "\n";
|
||||
os << " - Type: ";
|
||||
GetType().Dump(thread);
|
||||
GetType().D();
|
||||
os << "\n";
|
||||
os << " - MinimumIntegerDigits: ";
|
||||
GetMinimumIntegerDigits().Dump(thread);
|
||||
GetMinimumIntegerDigits().D();
|
||||
os << "\n";
|
||||
os << " - MinimumFractionDigits: ";
|
||||
GetMinimumFractionDigits().Dump(thread);
|
||||
GetMinimumFractionDigits().D();
|
||||
os << "\n";
|
||||
os << " - MaximumFractionDigits: ";
|
||||
GetMaximumFractionDigits().Dump(thread);
|
||||
GetMaximumFractionDigits().D();
|
||||
os << "\n";
|
||||
os << " - MinimumSignificantDigits: ";
|
||||
GetMinimumSignificantDigits().Dump(thread);
|
||||
GetMinimumSignificantDigits().D();
|
||||
os << "\n";
|
||||
os << " - MaximumSignificantDigits: ";
|
||||
GetMaximumSignificantDigits().Dump(thread);
|
||||
GetMaximumSignificantDigits().D();
|
||||
os << "\n";
|
||||
os << " - RoundingType: ";
|
||||
GetRoundingType().Dump(thread);
|
||||
GetRoundingType().D();
|
||||
os << "\n";
|
||||
os << " - IcuPR: ";
|
||||
GetIcuPR().Dump(thread);
|
||||
GetIcuPR().D();
|
||||
os << "\n";
|
||||
os << " - IcuNF: ";
|
||||
GetIcuNF().Dump(thread);
|
||||
GetIcuNF().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1783,16 +1786,16 @@ void JSPluralRules::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSGeneratorObject::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - GeneratorState: ";
|
||||
GetGeneratorState().Dump(thread);
|
||||
GetGeneratorState().D();
|
||||
os << "\n";
|
||||
os << " - GeneratorContext: ";
|
||||
GetGeneratorContext().Dump(thread);
|
||||
GetGeneratorContext().D();
|
||||
os << "\n";
|
||||
os << " - ResumeResult: ";
|
||||
GetResumeResult().Dump(thread);
|
||||
GetResumeResult().D();
|
||||
os << "\n";
|
||||
os << " - ResumeMode: ";
|
||||
GetResumeMode().Dump(thread);
|
||||
GetResumeMode().D();
|
||||
os << "\n";
|
||||
JSObject::Dump(thread, os);
|
||||
}
|
||||
@@ -1800,32 +1803,32 @@ void JSGeneratorObject::Dump(JSThread *thread, std::ostream &os) const
|
||||
void JSAsyncFuncObject::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Promise: ";
|
||||
GetPromise().Dump(thread);
|
||||
GetPromise().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void GeneratorContext::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - RegsArray: ";
|
||||
GetRegsArray().Dump(thread);
|
||||
GetRegsArray().D();
|
||||
os << "\n";
|
||||
os << " - Method: ";
|
||||
GetMethod().Dump(thread);
|
||||
GetMethod().D();
|
||||
os << "\n";
|
||||
os << " - Acc: ";
|
||||
GetAcc().Dump(thread);
|
||||
GetAcc().D();
|
||||
os << "\n";
|
||||
os << " - NRegs: ";
|
||||
GetNRegs().Dump(thread);
|
||||
GetNRegs().D();
|
||||
os << "\n";
|
||||
os << " - BCOffset: ";
|
||||
GetBCOffset().Dump(thread);
|
||||
GetBCOffset().D();
|
||||
os << "\n";
|
||||
os << " - GeneratorObject: ";
|
||||
GetGeneratorObject().Dump(thread);
|
||||
GetGeneratorObject().D();
|
||||
os << "\n";
|
||||
os << " - LexicalEnv: ";
|
||||
GetLexicalEnv().Dump(thread);
|
||||
GetLexicalEnv().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
@@ -1837,53 +1840,53 @@ void ProtoChangeMarker::Dump(JSThread *thread, std::ostream &os) const
|
||||
void ProtoChangeDetails::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - ChangeListener: ";
|
||||
GetChangeListener().Dump(thread);
|
||||
GetChangeListener().D();
|
||||
os << "\n";
|
||||
os << " - RegisterIndex: ";
|
||||
GetRegisterIndex().Dump(thread);
|
||||
GetRegisterIndex().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void LexicalFunction::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Name: ";
|
||||
GetName().Dump(thread);
|
||||
GetName().D();
|
||||
os << "\n";
|
||||
os << " - NumberVRegs: ";
|
||||
GetNumberVRegs().Dump(thread);
|
||||
GetNumberVRegs().D();
|
||||
os << "\n";
|
||||
os << " - NumberICSlots: ";
|
||||
GetNumberICSlots().Dump(thread);
|
||||
GetNumberICSlots().D();
|
||||
os << "\n";
|
||||
os << " - Bytecode: ";
|
||||
GetBytecode().Dump(thread);
|
||||
GetBytecode().D();
|
||||
os << "\n";
|
||||
os << " - Program: ";
|
||||
GetProgram().Dump(thread);
|
||||
GetProgram().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void JSFunctionExtraInfo::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - Callback: ";
|
||||
GetCallback().Dump(thread);
|
||||
GetCallback().D();
|
||||
os << "\n";
|
||||
os << " - Data: ";
|
||||
GetData().Dump(thread);
|
||||
GetData().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void MachineCode::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - InstructionSizeInBytes: ";
|
||||
GetInstructionSizeInBytes().Dump(thread);
|
||||
GetInstructionSizeInBytes().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void EcmaModule::Dump(JSThread *thread, std::ostream &os) const
|
||||
{
|
||||
os << " - NameDictionary: ";
|
||||
GetNameDictionary().Dump(thread);
|
||||
GetNameDictionary().D();
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
@@ -2287,13 +2290,13 @@ void JSObject::DumpForSnapshot(JSThread *thread, std::vector<std::pair<CString,
|
||||
}
|
||||
|
||||
if (!properties->IsDictionaryMode()) {
|
||||
JSTaggedValue attrs = jshclass->GetAttributes();
|
||||
JSTaggedValue attrs = jshclass->GetLayout();
|
||||
if (attrs.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetTaggedObject());
|
||||
int propNumber = jshclass->GetPropertiesNumber();
|
||||
int propNumber = jshclass->NumberOfProps();
|
||||
for (int i = 0; i < propNumber; i++) {
|
||||
JSTaggedValue key = layoutInfo->GetKey(i);
|
||||
PropertyAttributes attr = layoutInfo->GetAttr(i);
|
||||
@@ -2302,7 +2305,7 @@ void JSObject::DumpForSnapshot(JSThread *thread, std::vector<std::pair<CString,
|
||||
if (attr.IsInlinedProps()) {
|
||||
val = GetPropertyInlinedProps(i);
|
||||
} else {
|
||||
val = properties->Get(i - JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS);
|
||||
val = properties->Get(i - jshclass->GetInlinedProperties());
|
||||
}
|
||||
|
||||
CString str;
|
||||
|
||||
@@ -19,49 +19,174 @@
|
||||
#include "ecmascript/mem/chunk.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
inline uintptr_t EcmaGlobalStorage::NewGlobalHandleImplement(CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *> *storage,
|
||||
Node *freeList, int32_t &count, JSTaggedType value)
|
||||
inline EcmaGlobalStorage::NodeList *EcmaGlobalStorage::NodeList::NodeToNodeList(
|
||||
EcmaGlobalStorage::Node *node)
|
||||
{
|
||||
if (count == GLOBAL_BLOCK_SIZE && freeList == nullptr) {
|
||||
uintptr_t ptr = ToUintPtr(node) - node->GetIndex() * sizeof(EcmaGlobalStorage::Node);
|
||||
return reinterpret_cast<NodeList *>(ptr);
|
||||
}
|
||||
|
||||
EcmaGlobalStorage::Node *EcmaGlobalStorage::NodeList::NewNode(JSTaggedType value)
|
||||
{
|
||||
if (IsFull()) {
|
||||
return nullptr;
|
||||
}
|
||||
Node *node = &nodeList_[index_++];
|
||||
node->SetPrev(nullptr);
|
||||
node->SetNext(usedList_);
|
||||
node->SetObject(value);
|
||||
node->SetFree(false);
|
||||
|
||||
if (usedList_ != nullptr) {
|
||||
usedList_->SetPrev(node);
|
||||
}
|
||||
usedList_ = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
void EcmaGlobalStorage::NodeList::FreeNode(EcmaGlobalStorage::Node *node)
|
||||
{
|
||||
if (node->GetPrev() != nullptr) {
|
||||
node->GetPrev()->SetNext(node->GetNext());
|
||||
}
|
||||
if (node->GetNext() != nullptr) {
|
||||
node->GetNext()->SetPrev(node->GetPrev());
|
||||
}
|
||||
if (node == usedList_) {
|
||||
usedList_ = node->GetNext();
|
||||
}
|
||||
node->SetPrev(nullptr);
|
||||
node->SetNext(freeList_);
|
||||
node->SetObject(JSTaggedValue::Undefined().GetRawData());
|
||||
node->SetFree(true);
|
||||
|
||||
if (freeList_ != nullptr) {
|
||||
freeList_->SetPrev(node);
|
||||
}
|
||||
freeList_ = node;
|
||||
}
|
||||
|
||||
EcmaGlobalStorage::Node *EcmaGlobalStorage::NodeList::GetFreeNode(JSTaggedType value)
|
||||
{
|
||||
Node *node = freeList_;
|
||||
if (node != nullptr) {
|
||||
freeList_ = node->GetNext();
|
||||
|
||||
node->SetPrev(nullptr);
|
||||
node->SetNext(usedList_);
|
||||
node->SetObject(value);
|
||||
node->SetFree(false);
|
||||
|
||||
if (usedList_ != nullptr) {
|
||||
usedList_->SetPrev(node);
|
||||
}
|
||||
usedList_ = node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void EcmaGlobalStorage::NodeList::LinkTo(NodeList *prev)
|
||||
{
|
||||
next_ = nullptr;
|
||||
prev_ = prev;
|
||||
prev_->next_ = this;
|
||||
}
|
||||
|
||||
void EcmaGlobalStorage::NodeList::RemoveList()
|
||||
{
|
||||
if (next_ != nullptr) {
|
||||
next_->SetPrev(prev_);
|
||||
}
|
||||
if (prev_ != nullptr) {
|
||||
prev_->SetNext(next_);
|
||||
}
|
||||
if (freeNext_ != nullptr) {
|
||||
freeNext_->SetFreePrev(freePrev_);
|
||||
}
|
||||
if (freePrev_ != nullptr) {
|
||||
freePrev_->SetFreeNext(freeNext_);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t EcmaGlobalStorage::NewGlobalHandleImplement(NodeList **storage, NodeList **freeList,
|
||||
bool isWeak, JSTaggedType value)
|
||||
{
|
||||
if ((*storage)->IsFull() && *freeList == nullptr) {
|
||||
// alloc new block
|
||||
auto block = chunk_->New<std::array<Node, GLOBAL_BLOCK_SIZE>>();
|
||||
storage->push_back(block);
|
||||
count = count - GLOBAL_BLOCK_SIZE;
|
||||
auto block = chunk_->New<NodeList>(isWeak);
|
||||
block->LinkTo(*storage);
|
||||
*storage = block;
|
||||
}
|
||||
|
||||
// use node in block first
|
||||
if (count != GLOBAL_BLOCK_SIZE) {
|
||||
storage->back()->at(count).SetNext(nullptr);
|
||||
storage->back()->at(count).SetObject(value);
|
||||
return storage->back()->at(count++).GetObjectAddress();
|
||||
Node *node = (*storage)->NewNode(value);
|
||||
if (node != nullptr) {
|
||||
return node->GetObjectAddress();
|
||||
}
|
||||
|
||||
// use free_list node
|
||||
Node *node = freeList;
|
||||
freeList = freeList->GetNext();
|
||||
node->SetNext(nullptr);
|
||||
node->SetObject(value);
|
||||
node = (*freeList)->GetFreeNode(value);
|
||||
ASSERT(node != nullptr);
|
||||
if (!(*freeList)->HasFreeNode()) {
|
||||
auto next = (*freeList)->GetFreeNext();
|
||||
(*freeList)->SetFreeNext(nullptr);
|
||||
(*freeList)->SetFreePrev(nullptr);
|
||||
if (next != nullptr) {
|
||||
next->SetFreePrev(nullptr);
|
||||
}
|
||||
*freeList = next;
|
||||
}
|
||||
return node->GetObjectAddress();
|
||||
}
|
||||
|
||||
inline uintptr_t EcmaGlobalStorage::NewGlobalHandle(JSTaggedType value)
|
||||
{
|
||||
return NewGlobalHandleImplement(globalNodes_, freeList_, count_, value);
|
||||
return NewGlobalHandleImplement(&lastGlobalNodes_, &freeListNodes_, false, value);
|
||||
}
|
||||
|
||||
inline void EcmaGlobalStorage::DisposeGlobalHandle(uintptr_t nodeAddr)
|
||||
{
|
||||
Node *node = reinterpret_cast<Node *>(nodeAddr);
|
||||
node->SetObject(JSTaggedValue::Undefined().GetRawData());
|
||||
auto freeList = freeList_;
|
||||
if (IsWeak(nodeAddr)) {
|
||||
freeList = weakFreeList_;
|
||||
if (node->IsFree()) {
|
||||
return;
|
||||
}
|
||||
if (freeList != nullptr) {
|
||||
node->SetNext(freeList->GetNext());
|
||||
freeList->SetNext(node);
|
||||
NodeList *list = NodeList::NodeToNodeList(node);
|
||||
list->FreeNode(node);
|
||||
|
||||
// If NodeList has no usage node, then delete NodeList
|
||||
NodeList **freeList = nullptr;
|
||||
NodeList **top = nullptr;
|
||||
NodeList **last = nullptr;
|
||||
if (list->IsWeak()) {
|
||||
freeList = &weakFreeListNodes_;
|
||||
top = &topWeakGlobalNodes_;
|
||||
last = &lastWeakGlobalNodes_;
|
||||
} else {
|
||||
freeList = node;
|
||||
freeList = &freeListNodes_;
|
||||
top = &topGlobalNodes_;
|
||||
last = &lastGlobalNodes_;
|
||||
}
|
||||
if (!list->HasUsagedNode() && (*top != *last)) {
|
||||
list->RemoveList();
|
||||
if (*freeList == list) {
|
||||
*freeList = list->GetNext();
|
||||
}
|
||||
if (*top == list) {
|
||||
*top = list->GetNext();
|
||||
}
|
||||
if (*last == list) {
|
||||
*last = list->GetPrev();
|
||||
}
|
||||
chunk_->Delete(list);
|
||||
} else {
|
||||
// Add to freeList
|
||||
if (list != *freeList && list->GetFreeNext() == nullptr && list->GetFreePrev() == nullptr) {
|
||||
list->SetFreeNext(*freeList);
|
||||
if (*freeList != nullptr) {
|
||||
(*freeList)->SetFreePrev(list);
|
||||
}
|
||||
*freeList = list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,22 +194,14 @@ inline uintptr_t EcmaGlobalStorage::SetWeak(uintptr_t nodeAddr)
|
||||
{
|
||||
auto value = reinterpret_cast<Node *>(nodeAddr)->GetObject();
|
||||
DisposeGlobalHandle(nodeAddr);
|
||||
return NewGlobalHandleImplement(weakGlobalNodes_, weakFreeList_, weakCount_, value);
|
||||
return NewGlobalHandleImplement(&lastWeakGlobalNodes_, &weakFreeListNodes_, true, value);
|
||||
}
|
||||
|
||||
inline bool EcmaGlobalStorage::IsWeak(uintptr_t nodeAddr) const
|
||||
inline bool EcmaGlobalStorage::IsWeak(uintptr_t addr) const
|
||||
{
|
||||
if (weakGlobalNodes_->empty()) {
|
||||
return false;
|
||||
}
|
||||
size_t pageSize = sizeof(Node) * GLOBAL_BLOCK_SIZE;
|
||||
for (size_t i = 0; i < weakGlobalNodes_->size(); i++) {
|
||||
auto block = weakGlobalNodes_->at(i);
|
||||
if (nodeAddr >= ToUintPtr(block) && nodeAddr < ToUintPtr(block) + pageSize) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
Node *node = reinterpret_cast<Node *>(addr);
|
||||
NodeList *list = NodeList::NodeToNodeList(node);
|
||||
return list->IsWeak();
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_ECMA_GLOABL_STORAGE_INL_H
|
||||
|
||||
@@ -29,21 +29,26 @@ public:
|
||||
explicit EcmaGlobalStorage(Chunk *chunk) : chunk_(chunk)
|
||||
{
|
||||
ASSERT(chunk != nullptr);
|
||||
globalNodes_ = chunk->New<CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *>>();
|
||||
weakGlobalNodes_ = chunk->New<CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *>>();
|
||||
};
|
||||
topGlobalNodes_ = lastGlobalNodes_ = chunk_->New<NodeList>(false);
|
||||
topWeakGlobalNodes_ = lastWeakGlobalNodes_ = chunk_->New<NodeList>(true);
|
||||
}
|
||||
|
||||
~EcmaGlobalStorage()
|
||||
{
|
||||
for (auto block : *globalNodes_) {
|
||||
chunk_->Delete(block);
|
||||
NodeList *next = topGlobalNodes_;
|
||||
NodeList *current = nullptr;
|
||||
while (next != nullptr) {
|
||||
current = next;
|
||||
next = current->GetNext();
|
||||
chunk_->Delete(current);
|
||||
}
|
||||
chunk_->Delete(globalNodes_);
|
||||
|
||||
for (auto block : *weakGlobalNodes_) {
|
||||
chunk_->Delete(block);
|
||||
next = topWeakGlobalNodes_;
|
||||
while (next != nullptr) {
|
||||
current = next;
|
||||
next = current->GetNext();
|
||||
chunk_->Delete(current);
|
||||
}
|
||||
chunk_->Delete(weakGlobalNodes_);
|
||||
}
|
||||
|
||||
class Node {
|
||||
@@ -68,6 +73,36 @@ public:
|
||||
next_ = node;
|
||||
}
|
||||
|
||||
Node *GetPrev() const
|
||||
{
|
||||
return prev_;
|
||||
}
|
||||
|
||||
void SetPrev(Node *node)
|
||||
{
|
||||
prev_ = node;
|
||||
}
|
||||
|
||||
int32_t GetIndex()
|
||||
{
|
||||
return index_;
|
||||
}
|
||||
|
||||
void SetIndex(int32_t index)
|
||||
{
|
||||
index_ = index;
|
||||
}
|
||||
|
||||
void SetFree(bool free)
|
||||
{
|
||||
isFree_ = free;
|
||||
}
|
||||
|
||||
bool IsFree() const
|
||||
{
|
||||
return isFree_;
|
||||
}
|
||||
|
||||
uintptr_t GetObjectAddress() const
|
||||
{
|
||||
return reinterpret_cast<uintptr_t>(&obj_);
|
||||
@@ -75,7 +110,110 @@ public:
|
||||
|
||||
private:
|
||||
JSTaggedType obj_;
|
||||
Node *next_;
|
||||
Node *next_ {nullptr};
|
||||
Node *prev_ {nullptr};
|
||||
int32_t index_ {-1};
|
||||
bool isFree_ {false};
|
||||
};
|
||||
|
||||
class NodeList {
|
||||
public:
|
||||
NodeList(bool isWeak) : isWeak_(isWeak)
|
||||
{
|
||||
for (int i = 0; i < GLOBAL_BLOCK_SIZE; i++) {
|
||||
nodeList_[i].SetIndex(i);
|
||||
}
|
||||
}
|
||||
~NodeList() = default;
|
||||
|
||||
inline static NodeList *NodeToNodeList(Node *node);
|
||||
|
||||
inline Node *NewNode(JSTaggedType value);
|
||||
inline Node *GetFreeNode(JSTaggedType value);
|
||||
inline void FreeNode(Node *node);
|
||||
|
||||
inline void LinkTo(NodeList *prev);
|
||||
inline void RemoveList();
|
||||
|
||||
inline bool IsFull()
|
||||
{
|
||||
return index_ >= GLOBAL_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
inline bool IsWeak()
|
||||
{
|
||||
return isWeak_;
|
||||
}
|
||||
|
||||
inline bool HasFreeNode()
|
||||
{
|
||||
return freeList_ != nullptr;
|
||||
}
|
||||
|
||||
inline bool HasUsagedNode()
|
||||
{
|
||||
return !IsFull() || usedList_ != nullptr;
|
||||
}
|
||||
|
||||
inline void SetNext(NodeList *next)
|
||||
{
|
||||
next_ = next;
|
||||
}
|
||||
inline NodeList *GetNext() const
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
inline void SetPrev(NodeList *prev)
|
||||
{
|
||||
prev_ = prev;
|
||||
}
|
||||
inline NodeList *GetPrev() const
|
||||
{
|
||||
return prev_;
|
||||
}
|
||||
|
||||
inline void SetFreeNext(NodeList *next)
|
||||
{
|
||||
freeNext_ = next;
|
||||
}
|
||||
inline NodeList *GetFreeNext() const
|
||||
{
|
||||
return freeNext_;
|
||||
}
|
||||
|
||||
inline void SetFreePrev(NodeList *prev)
|
||||
{
|
||||
freePrev_ = prev;
|
||||
}
|
||||
inline NodeList *GetFreePrev() const
|
||||
{
|
||||
return freePrev_;
|
||||
}
|
||||
|
||||
template<class Callback>
|
||||
inline void IterateUsageGlobal(Callback callback)
|
||||
{
|
||||
Node *next = usedList_;
|
||||
Node *current = nullptr;
|
||||
while (next != nullptr) {
|
||||
current = next;
|
||||
next = current->GetNext();
|
||||
ASSERT(current != next);
|
||||
callback(current);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Node nodeList_[GLOBAL_BLOCK_SIZE]; // all
|
||||
Node *freeList_ {nullptr}; // dispose node
|
||||
Node *usedList_ {nullptr}; // usage node
|
||||
int32_t index_ {0};
|
||||
bool isWeak_ {false};
|
||||
NodeList *next_ {nullptr};
|
||||
NodeList *prev_ {nullptr};
|
||||
NodeList *freeNext_ {nullptr};
|
||||
NodeList *freePrev_ {nullptr};
|
||||
};
|
||||
|
||||
inline uintptr_t NewGlobalHandle(JSTaggedType value);
|
||||
@@ -83,40 +221,46 @@ public:
|
||||
inline uintptr_t SetWeak(uintptr_t addr);
|
||||
inline bool IsWeak(uintptr_t addr) const;
|
||||
|
||||
inline CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *> *GetNodes() const
|
||||
template<class Callback>
|
||||
void IterateUsageGlobal(Callback callback)
|
||||
{
|
||||
return globalNodes_;
|
||||
NodeList *next = topGlobalNodes_;
|
||||
NodeList *current = nullptr;
|
||||
while (next != nullptr) {
|
||||
current = next;
|
||||
next = current->GetNext();
|
||||
ASSERT(current != next);
|
||||
current->IterateUsageGlobal(callback);
|
||||
}
|
||||
}
|
||||
|
||||
inline CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *> *GetWeakNodes() const
|
||||
template<class Callback>
|
||||
void IterateWeakUsageGlobal(Callback callback)
|
||||
{
|
||||
return weakGlobalNodes_;
|
||||
}
|
||||
|
||||
inline int32_t GetCount() const
|
||||
{
|
||||
return count_;
|
||||
}
|
||||
|
||||
inline int32_t GetWeakCount() const
|
||||
{
|
||||
return weakCount_;
|
||||
NodeList *next = topWeakGlobalNodes_;
|
||||
NodeList *current = nullptr;
|
||||
while (next != nullptr) {
|
||||
current = next;
|
||||
next = current->GetNext();
|
||||
ASSERT(current != next);
|
||||
current->IterateUsageGlobal(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NO_COPY_SEMANTIC(EcmaGlobalStorage);
|
||||
NO_MOVE_SEMANTIC(EcmaGlobalStorage);
|
||||
|
||||
inline uintptr_t NewGlobalHandleImplement(CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *> *storage, Node *freeList,
|
||||
int32_t &count, JSTaggedType value);
|
||||
inline uintptr_t NewGlobalHandleImplement(NodeList **storage, NodeList **freeList, bool isWeak, JSTaggedType value);
|
||||
|
||||
Chunk *chunk_ {nullptr};
|
||||
CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *> *globalNodes_ {nullptr};
|
||||
int32_t count_ {GLOBAL_BLOCK_SIZE};
|
||||
Node *freeList_ {nullptr};
|
||||
CVector<std::array<Node, GLOBAL_BLOCK_SIZE> *> *weakGlobalNodes_ {nullptr};
|
||||
int32_t weakCount_ {GLOBAL_BLOCK_SIZE};
|
||||
Node *weakFreeList_ {nullptr};
|
||||
NodeList *topGlobalNodes_ {nullptr};
|
||||
NodeList *lastGlobalNodes_ {nullptr};
|
||||
NodeList *freeListNodes_ {nullptr};
|
||||
|
||||
NodeList *topWeakGlobalNodes_ {nullptr};
|
||||
NodeList *lastWeakGlobalNodes_ {nullptr};
|
||||
NodeList *weakFreeListNodes_ {nullptr};
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_ECMA_GLOABL_STORAGE_H
|
||||
|
||||
@@ -24,10 +24,12 @@ inline EcmaHandleScope::EcmaHandleScope(JSThread *thread)
|
||||
: thread_(thread), prevNext_(thread->handleScopeStorageNext_), prevEnd_(thread->handleScopeStorageEnd_),
|
||||
prevHandleStorageIndex_(thread->currentHandleStorageIndex_)
|
||||
{
|
||||
thread->HandleScopeCountAdd();
|
||||
}
|
||||
|
||||
inline EcmaHandleScope::~EcmaHandleScope()
|
||||
{
|
||||
thread_->HandleScopeCountDec();
|
||||
thread_->handleScopeStorageNext_ = prevNext_;
|
||||
if (thread_->handleScopeStorageEnd_ != prevEnd_) {
|
||||
thread_->handleScopeStorageEnd_ = prevEnd_;
|
||||
@@ -37,6 +39,8 @@ inline EcmaHandleScope::~EcmaHandleScope()
|
||||
|
||||
uintptr_t EcmaHandleScope::NewHandle(JSThread *thread, JSTaggedType value)
|
||||
{
|
||||
// Each Handle must be managed by HandleScope, otherwise it may cause Handle leakage.
|
||||
ASSERT(thread->handleScopeCount_ > 0);
|
||||
auto result = thread->handleScopeStorageNext_;
|
||||
if (result == thread->handleScopeStorageEnd_) {
|
||||
result = reinterpret_cast<JSTaggedType *>(thread->ExpandHandleStorage());
|
||||
|
||||
@@ -586,3 +586,7 @@ groups:
|
||||
prefix: ecma
|
||||
format: [pref_op_id_32_v_8]
|
||||
properties: [string_id]
|
||||
- sig: ecma.ldfunction
|
||||
acc: out:top
|
||||
prefix: ecma
|
||||
format: [pref_op_none]
|
||||
@@ -29,6 +29,8 @@
|
||||
#define LOG_ECMA(type) \
|
||||
LOG(type, ECMASCRIPT) << __func__ << " Line:" << __LINE__ << " " // NOLINT(bugprone-lambda-function-name)
|
||||
|
||||
#define ECMA_GC_LOG() LOG(DEBUG, ECMASCRIPT) << " ecmascript gc log: "
|
||||
|
||||
/* Note: We can't statically decide the element type is a primitive or heap object, especially for */
|
||||
/* dynamically-typed languages like JavaScript. So we simply skip the read-barrier. */
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
@@ -396,9 +398,77 @@
|
||||
visitor(this, ObjectSlot(ToUintPtr(this) + BEGIN_OFFSET), ObjectSlot(ToUintPtr(this) + SIZE)); \
|
||||
}
|
||||
|
||||
#if ECMASCRIPT_ENABLE_CAST_CHECK
|
||||
#define CAST_CHECK(CAST_TYPE, CHECK_METHOD) \
|
||||
static inline CAST_TYPE *Cast(ObjectHeader *object) \
|
||||
{ \
|
||||
if (!JSTaggedValue(object).CHECK_METHOD()) { \
|
||||
std::abort(); \
|
||||
} \
|
||||
return static_cast<CAST_TYPE *>(object); \
|
||||
} \
|
||||
static inline const CAST_TYPE *ConstCast(const ObjectHeader *object) \
|
||||
{ \
|
||||
if (!JSTaggedValue(object).CHECK_METHOD()) { \
|
||||
std::abort(); \
|
||||
} \
|
||||
return static_cast<const CAST_TYPE *>(object); \
|
||||
}
|
||||
# else
|
||||
#define CAST_CHECK(CAST_TYPE, CHECK_METHOD) \
|
||||
static inline CAST_TYPE *Cast(ObjectHeader *object) \
|
||||
{ \
|
||||
ASSERT(JSTaggedValue(object).CHECK_METHOD()); \
|
||||
return static_cast<CAST_TYPE *>(object); \
|
||||
} \
|
||||
static const inline CAST_TYPE *ConstCast(const ObjectHeader *object) \
|
||||
{ \
|
||||
ASSERT(JSTaggedValue(object).CHECK_METHOD()); \
|
||||
return static_cast<const CAST_TYPE *>(object); \
|
||||
}
|
||||
|
||||
#define CAST_NO_CHECK(CAST_TYPE) \
|
||||
static inline CAST_TYPE *Cast(ObjectHeader *object) \
|
||||
{ \
|
||||
return static_cast<CAST_TYPE *>(object); \
|
||||
} \
|
||||
static const inline CAST_TYPE *ConstCast(const ObjectHeader *object) \
|
||||
{ \
|
||||
return static_cast<const CAST_TYPE *>(object); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ECMASCRIPT_ENABLE_CAST_CHECK
|
||||
#define CAST_CHECK_TAGGEDVALUE(CAST_TYPE, CHECK_METHOD) \
|
||||
static inline CAST_TYPE *Cast(JSTaggedValue value) \
|
||||
{ \
|
||||
if (value.IsHeapObject() && value.GetTaggedObject()->GetClass()->CHECK_METHOD()) { \
|
||||
return static_cast<CAST_TYPE *>(value.GetTaggedObject()); \
|
||||
} \
|
||||
std::abort(); \
|
||||
}
|
||||
# else
|
||||
#define CAST_CHECK_TAGGEDVALUE(CAST_TYPE, CHECK_METHOD) \
|
||||
static inline CAST_TYPE *Cast(JSTaggedValue value) \
|
||||
{ \
|
||||
ASSERT(value.IsHeapObject() && value.GetTaggedObject()->GetClass()->CHECK_METHOD()); \
|
||||
return static_cast<CAST_TYPE *>(value.GetTaggedObject()); \
|
||||
}
|
||||
#endif
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CHECK_DUMP_FILEDS(begin, end, num) \
|
||||
LOG_IF(num != (end - begin) / JSTaggedValue::TaggedTypeSize(), FATAL, RUNTIME) \
|
||||
<< "Fileds in obj are not in dump list. ";
|
||||
#define CHECK_DUMP_FILEDS(begin, end, num) \
|
||||
LOG_IF(num != (end - begin) / JSTaggedValue::TaggedTypeSize(), FATAL, RUNTIME) \
|
||||
<< "Fileds in obj are not in dump list. ";
|
||||
|
||||
#define CHECK_OBJECT_SIZE(size) \
|
||||
if (size == 0) { \
|
||||
LOG(FATAL, ECMASCRIPT) << __func__ << " Line: " << __LINE__ << " objectSize is " << size; \
|
||||
}
|
||||
|
||||
#define CHECK_REGION_END(begin, end) \
|
||||
if (begin > end) { \
|
||||
LOG(FATAL, ECMASCRIPT) << __func__ << " Line: " << __LINE__ << " begin: " << begin << " end: " << end; \
|
||||
}
|
||||
|
||||
#endif // ECMASCRIPT_ECMA_MACROS_H
|
||||
|
||||
+37
-65
@@ -22,8 +22,6 @@
|
||||
#include "ecmascript/tagged_dictionary.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
static constexpr uint32_t DICTIONART_CAP = 4;
|
||||
constexpr uint32_t PREVMODULE_CAP = 2;
|
||||
|
||||
JSHandle<JSTaggedValue> EcmaModule::GetItem(const JSThread *thread, JSHandle<JSTaggedValue> itemName)
|
||||
{
|
||||
@@ -37,19 +35,16 @@ JSHandle<JSTaggedValue> EcmaModule::GetItem(const JSThread *thread, JSHandle<JST
|
||||
}
|
||||
|
||||
void EcmaModule::AddItem(const JSThread *thread, JSHandle<EcmaModule> module, JSHandle<JSTaggedValue> itemName,
|
||||
JSHandle<JSTaggedValue> itemValue)
|
||||
JSHandle<JSTaggedValue> itemValue)
|
||||
{
|
||||
JSHandle<JSTaggedValue> data(thread, module->GetNameDictionary());
|
||||
JSMutableHandle<JSTaggedValue> data(thread, module->GetNameDictionary());
|
||||
if (data->IsUndefined()) {
|
||||
JSHandle<NameDictionary> dict(thread, NameDictionary::Create(thread, DICTIONART_CAP));
|
||||
NameDictionary *newDict = NameDictionary::Put(thread, dict, itemName, itemValue, PropertyAttributes::Default());
|
||||
module->SetNameDictionary(thread, JSTaggedValue(newDict));
|
||||
} else {
|
||||
JSHandle<NameDictionary> dataDict = JSHandle<NameDictionary>::Cast(data);
|
||||
NameDictionary *newDict =
|
||||
NameDictionary::Put(thread, dataDict, itemName, itemValue, PropertyAttributes::Default());
|
||||
module->SetNameDictionary(thread, JSTaggedValue(newDict));
|
||||
data.Update(NameDictionary::Create(thread, DEAULT_DICTIONART_CAPACITY));
|
||||
}
|
||||
JSHandle<NameDictionary> dataDict = JSHandle<NameDictionary>::Cast(data);
|
||||
JSHandle<NameDictionary> newDict =
|
||||
NameDictionary::Put(thread, dataDict, itemName, itemValue, PropertyAttributes::Default());
|
||||
module->SetNameDictionary(thread, newDict);
|
||||
}
|
||||
|
||||
void EcmaModule::RemoveItem(const JSThread *thread, JSHandle<EcmaModule> module, JSHandle<JSTaggedValue> itemName)
|
||||
@@ -61,13 +56,13 @@ void EcmaModule::RemoveItem(const JSThread *thread, JSHandle<EcmaModule> module,
|
||||
JSHandle<NameDictionary> moduleItems(data);
|
||||
int entry = moduleItems->FindEntry(itemName.GetTaggedValue());
|
||||
if (entry != -1) {
|
||||
NameDictionary *newDict = NameDictionary::Remove(thread, moduleItems, entry);
|
||||
module->SetNameDictionary(thread, JSTaggedValue(newDict));
|
||||
JSHandle<NameDictionary> newDict = NameDictionary::Remove(thread, moduleItems, entry);
|
||||
module->SetNameDictionary(thread, newDict);
|
||||
}
|
||||
}
|
||||
|
||||
void EcmaModule::CopyModuleInternal(const JSThread *thread, JSHandle<EcmaModule> dstModule,
|
||||
JSHandle<EcmaModule> srcModule)
|
||||
JSHandle<EcmaModule> srcModule)
|
||||
{
|
||||
JSHandle<NameDictionary> moduleItems(thread,
|
||||
NameDictionary::Cast(srcModule->GetNameDictionary().GetTaggedObject()));
|
||||
@@ -112,7 +107,7 @@ void EcmaModule::DebugPrint(const JSThread *thread, const CString &caller)
|
||||
|
||||
ModuleManager::ModuleManager(EcmaVM *vm) : vm_(vm)
|
||||
{
|
||||
ecmaModules_ = JSTaggedValue(NameDictionary::Create(vm_->GetJSThread(), DICTIONART_CAP));
|
||||
ecmaModules_ = NameDictionary::Create(vm_->GetJSThread(), DEAULT_DICTIONART_CAPACITY).GetTaggedValue();
|
||||
}
|
||||
|
||||
// class ModuleManager
|
||||
@@ -122,7 +117,7 @@ void ModuleManager::AddModule(JSHandle<JSTaggedValue> moduleName, JSHandle<JSTag
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread);
|
||||
JSHandle<NameDictionary> dict(thread, ecmaModules_);
|
||||
ecmaModules_ =
|
||||
JSTaggedValue(NameDictionary::Put(thread, dict, moduleName, module, PropertyAttributes::Default()));
|
||||
NameDictionary::Put(thread, dict, moduleName, module, PropertyAttributes::Default()).GetTaggedValue();
|
||||
}
|
||||
|
||||
void ModuleManager::RemoveModule(JSHandle<JSTaggedValue> moduleName)
|
||||
@@ -132,7 +127,7 @@ void ModuleManager::RemoveModule(JSHandle<JSTaggedValue> moduleName)
|
||||
JSHandle<NameDictionary> moduleItems(thread, ecmaModules_);
|
||||
int entry = moduleItems->FindEntry(moduleName.GetTaggedValue());
|
||||
if (entry != -1) {
|
||||
ecmaModules_ = JSTaggedValue(NameDictionary::Remove(thread, moduleItems, entry));
|
||||
ecmaModules_ = NameDictionary::Remove(thread, moduleItems, entry).GetTaggedValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,13 +143,13 @@ JSHandle<JSTaggedValue> ModuleManager::GetModule(const JSThread *thread,
|
||||
|
||||
CString ModuleManager::GenerateModuleFullPath(const std::string ¤tPathFile, const CString &relativeFile)
|
||||
{
|
||||
if (relativeFile.find("./") != 0 && relativeFile.find("../") != 0) { // not start with "./" or "../"
|
||||
return relativeFile; // not relative
|
||||
if (relativeFile.find("./") != 0 && relativeFile.find("../") != 0) { // not start with "./" or "../"
|
||||
return relativeFile; // not relative
|
||||
}
|
||||
|
||||
auto slashPos = currentPathFile.find_last_of('/');
|
||||
if (slashPos == std::string::npos) {
|
||||
return relativeFile; // no need to process
|
||||
return relativeFile; // no need to process
|
||||
}
|
||||
|
||||
auto dotPos = relativeFile.find_last_of(".");
|
||||
@@ -163,30 +158,38 @@ CString ModuleManager::GenerateModuleFullPath(const std::string ¤tPathFile
|
||||
}
|
||||
|
||||
CString fullPath;
|
||||
fullPath.append(currentPathFile.substr(0, slashPos + 1)); // 1: with "/"
|
||||
fullPath.append(currentPathFile.substr(0, slashPos + 1)); // 1: with "/"
|
||||
fullPath.append(relativeFile.substr(0, dotPos));
|
||||
fullPath.append(".abc"); // ".js" -> ".abc"
|
||||
fullPath.append(".abc"); // ".js" -> ".abc"
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
const CString &ModuleManager::GetCurrentExportModuleName()
|
||||
{
|
||||
return moduleStack_.GetTop();
|
||||
return moduleNames_.back();
|
||||
}
|
||||
|
||||
void ModuleManager::SetCurrentExportModuleName(const std::string_view &moduleFile)
|
||||
{
|
||||
moduleStack_.PushModule(CString(moduleFile)); // xx/xx/x.abc
|
||||
moduleNames_.emplace_back(CString(moduleFile)); // xx/xx/x.abc
|
||||
}
|
||||
|
||||
void ModuleManager::RestoreCurrentExportModuleName()
|
||||
{
|
||||
moduleStack_.PopModule();
|
||||
auto s = moduleNames_.size();
|
||||
if (s > 0) {
|
||||
moduleNames_.resize(s - 1);
|
||||
return;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
const CString &ModuleManager::GetPrevExportModuleName()
|
||||
{
|
||||
return moduleStack_.GetPrevModule();
|
||||
static const int MINIMUM_COUNT = 2;
|
||||
auto count = moduleNames_.size();
|
||||
ASSERT(count >= MINIMUM_COUNT);
|
||||
return moduleNames_[count - MINIMUM_COUNT];
|
||||
}
|
||||
|
||||
void ModuleManager::AddModuleItem(const JSThread *thread, JSHandle<JSTaggedValue> itemName,
|
||||
@@ -237,44 +240,13 @@ void ModuleManager::CopyModule(const JSThread *thread, JSHandle<JSTaggedValue> s
|
||||
|
||||
void ModuleManager::DebugPrint([[maybe_unused]] const JSThread *thread, [[maybe_unused]] const CString &caller)
|
||||
{
|
||||
moduleStack_.DebugPrint(std::cout);
|
||||
std::cout << "ModuleStack:";
|
||||
for_each(moduleNames_.cbegin(),
|
||||
moduleNames_.cend(),
|
||||
[](const CString& s)->void {
|
||||
std::cout << s << " ";
|
||||
});
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
// class ModuleStack
|
||||
void ModuleStack::PushModule(const CString &moduleName)
|
||||
{
|
||||
data_.push_back(moduleName);
|
||||
}
|
||||
|
||||
void ModuleStack::PopModule()
|
||||
{
|
||||
data_.pop_back();
|
||||
}
|
||||
|
||||
const CString &ModuleStack::GetTop()
|
||||
{
|
||||
return data_.back();
|
||||
}
|
||||
|
||||
const CString &ModuleStack::GetPrevModule()
|
||||
{
|
||||
if (data_.size() >= PREVMODULE_CAP) {
|
||||
return data_[data_.size() - PREVMODULE_CAP];
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void ModuleStack::DebugPrint(std::ostream &dump) const
|
||||
{
|
||||
dump << "ModuleStack:\n";
|
||||
if (data_.empty()) {
|
||||
dump << "empty \n";
|
||||
return;
|
||||
}
|
||||
// NOLINTNEXTLINE(hicpp-use-auto, modernize-use-auto)
|
||||
for (std::vector<CString>::const_reverse_iterator it = data_.rbegin(); it != data_.rend(); it++) {
|
||||
dump << *it << "\n";
|
||||
}
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
|
||||
void DebugPrint(const JSThread *thread, const CString &caller);
|
||||
|
||||
static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4;
|
||||
|
||||
static constexpr size_t NAME_DICTIONARY_OFFSET = ECMAObject::SIZE;
|
||||
ACCESSORS(NameDictionary, NAME_DICTIONARY_OFFSET, SIZE)
|
||||
|
||||
@@ -53,24 +55,6 @@ protected:
|
||||
friend class ModuleManager;
|
||||
};
|
||||
|
||||
class ModuleStack {
|
||||
public:
|
||||
ModuleStack() = default;
|
||||
~ModuleStack() = default;
|
||||
|
||||
NO_COPY_SEMANTIC(ModuleStack);
|
||||
NO_MOVE_SEMANTIC(ModuleStack);
|
||||
|
||||
void PushModule(const CString &moduleName);
|
||||
void PopModule();
|
||||
const CString &GetTop();
|
||||
const CString &GetPrevModule();
|
||||
void DebugPrint(std::ostream &dump) const;
|
||||
|
||||
private:
|
||||
std::vector<CString> data_;
|
||||
};
|
||||
|
||||
class ModuleManager {
|
||||
public:
|
||||
explicit ModuleManager(EcmaVM *vm);
|
||||
@@ -102,15 +86,16 @@ public:
|
||||
void DebugPrint(const JSThread *thread, const CString &caller);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t DEAULT_DICTIONART_CAPACITY = 4;
|
||||
|
||||
NO_COPY_SEMANTIC(ModuleManager);
|
||||
NO_MOVE_SEMANTIC(ModuleManager);
|
||||
|
||||
EcmaVM *vm_{nullptr};
|
||||
JSTaggedValue ecmaModules_{JSTaggedValue::Hole()};
|
||||
ModuleStack moduleStack_;
|
||||
std::vector<CString> moduleNames_{DEAULT_DICTIONART_CAPACITY};
|
||||
|
||||
friend class EcmaVM;
|
||||
friend class ModuleStack;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
|
||||
@@ -415,7 +415,7 @@ uint32_t EcmaString::ComputeHashcode() const
|
||||
hash = ComputeHashForData(GetDataUtf16(), GetLength());
|
||||
}
|
||||
} else {
|
||||
ASSERT(static_cast<size_t>(GetLength()) < (std::numeric_limits<size_t>::max() >> 1U));
|
||||
ASSERT(static_cast<size_t>(GetLength())<(std::numeric_limits<size_t>::max()>>1U));
|
||||
hash = ComputeHashForData(GetDataUtf16(), GetLength());
|
||||
}
|
||||
return hash;
|
||||
|
||||
+41
-20
@@ -20,21 +20,21 @@
|
||||
#include "ecmascript/builtins/builtins_regexp.h"
|
||||
#include "ecmascript/class_linker/panda_file_translator.h"
|
||||
#include "ecmascript/class_linker/program_object-inl.h"
|
||||
#include "ecmascript/cpu_profiler/cpu_profiler.h"
|
||||
#include "ecmascript/ecma_module.h"
|
||||
#include "ecmascript/ecma_string_table.h"
|
||||
#include "ecmascript/global_dictionary.h"
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/global_env_constants-inl.h"
|
||||
#include "ecmascript/global_env_constants.h"
|
||||
#include "ecmascript/ic/properties_cache-inl.h"
|
||||
#include "ecmascript/internal_call_params.h"
|
||||
#include "ecmascript/jobs/micro_job_queue.h"
|
||||
#include "ecmascript/js_arraybuffer.h"
|
||||
#include "ecmascript/js_for_in_iterator.h"
|
||||
#include "ecmascript/js_invoker.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "ecmascript/mem/concurrent_marker.h"
|
||||
#include "ecmascript/mem/heap.h"
|
||||
#include "ecmascript/tagged_dictionary.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/platform/platform.h"
|
||||
#include "ecmascript/regexp/regexp_parser_cache.h"
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "ecmascript/snapshot/mem/snapshot_serialize.h"
|
||||
#include "ecmascript/symbol_table.h"
|
||||
#include "ecmascript/tagged_array-inl.h"
|
||||
#include "ecmascript/tagged_dictionary.h"
|
||||
#include "ecmascript/tagged_queue-inl.h"
|
||||
#include "ecmascript/tagged_queue.h"
|
||||
#include "ecmascript/template_map.h"
|
||||
@@ -127,8 +128,6 @@ bool EcmaVM::Initialize()
|
||||
RuntimeTrampolines::InitializeRuntimeTrampolines(thread_);
|
||||
|
||||
auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
|
||||
|
||||
propertiesCache_ = new PropertiesCache();
|
||||
regExpParserCache_ = new RegExpParserCache();
|
||||
heap_ = new Heap(this);
|
||||
heap_->Initialize();
|
||||
@@ -139,11 +138,12 @@ bool EcmaVM::Initialize()
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
if (!snapshotDeserializeEnable_ || !VerifyFilePath(fileName_)) {
|
||||
LOG_ECMA(DEBUG) << "EcmaVM::Initialize run builtins";
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
|
||||
JSHandle<JSHClass> dynClassClassHandle = factory_->NewEcmaDynClass(nullptr, JSHClass::SIZE, JSType::HCLASS);
|
||||
JSHandle<JSHClass> dynClassClassHandle =
|
||||
factory_->NewEcmaDynClassClass(nullptr, JSHClass::SIZE, JSType::HCLASS);
|
||||
JSHClass *dynclass = reinterpret_cast<JSHClass *>(dynClassClassHandle.GetTaggedValue().GetTaggedObject());
|
||||
dynclass->SetClass(dynclass);
|
||||
JSHandle<JSHClass> globalEnvClass =
|
||||
@@ -159,13 +159,13 @@ bool EcmaVM::Initialize()
|
||||
globalConst->InitGlobalConstant(thread_);
|
||||
globalEnv->SetEmptyArray(thread_, factory_->NewEmptyArray());
|
||||
globalEnv->SetEmptyLayoutInfo(thread_, factory_->CreateLayoutInfo(0));
|
||||
globalEnv->SetRegisterSymbols(thread_, JSTaggedValue(SymbolTable::Create(thread_)));
|
||||
globalEnv->SetGlobalRecord(thread_, JSTaggedValue(GlobalDictionary::Create(thread_)));
|
||||
globalEnv->SetRegisterSymbols(thread_, SymbolTable::Create(thread_));
|
||||
globalEnv->SetGlobalRecord(thread_, GlobalDictionary::Create(thread_));
|
||||
JSTaggedValue emptyStr = thread_->GlobalConstants()->GetEmptyString();
|
||||
stringTable_->InternEmptyString(EcmaString::Cast(emptyStr.GetTaggedObject()));
|
||||
globalEnv->SetEmptyTaggedQueue(thread_, factory_->NewTaggedQueue(0));
|
||||
globalEnv->SetTemplateMap(thread_, JSTaggedValue(TemplateMap::Create(thread_)));
|
||||
globalEnv->SetRegisterSymbols(GetJSThread(), JSTaggedValue(SymbolTable::Create(GetJSThread())));
|
||||
globalEnv->SetTemplateMap(thread_, TemplateMap::Create(thread_));
|
||||
globalEnv->SetRegisterSymbols(GetJSThread(), SymbolTable::Create(GetJSThread()));
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT
|
||||
std::string moduleFile = options_.GetStubModuleFile();
|
||||
thread_->LoadFastStubModule(moduleFile.c_str());
|
||||
@@ -193,6 +193,24 @@ bool EcmaVM::Initialize()
|
||||
InitializeFinish();
|
||||
notificationManager_->VmStartEvent();
|
||||
notificationManager_->VmInitializationEvent(0);
|
||||
Platform::GetCurrentPlatform()->PostTask(std::make_unique<TrimNewSpaceLimitTask>(heap_));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EcmaVM::TrimNewSpaceLimitTask::Run(uint32_t threadIndex)
|
||||
{
|
||||
for (uint32_t i = 0; i < THREAD_SLEEP_COUNT; i++) {
|
||||
if (IsTerminate()) {
|
||||
return false;
|
||||
}
|
||||
usleep(THREAD_SLEEP_TIME);
|
||||
}
|
||||
|
||||
if (!IsTerminate() && heap_->GetMemController()->IsInAppStartup()) {
|
||||
heap_->SetFromSpaceMaximumCapacity(SEMI_SPACE_SIZE_CAPACITY);
|
||||
heap_->SetNewSpaceMaximumCapacity(SEMI_SPACE_SIZE_CAPACITY);
|
||||
heap_->ResetAppStartup();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -241,8 +259,8 @@ bool EcmaVM::InitializeFinish()
|
||||
}
|
||||
EcmaVM::~EcmaVM()
|
||||
{
|
||||
Platform::GetCurrentPlatform()->Destory();
|
||||
vmInitialized_ = false;
|
||||
Platform::GetCurrentPlatform()->Destroy();
|
||||
ClearNativeMethodsData();
|
||||
|
||||
if (runtimeStat_ != nullptr && runtimeStatEnabled_) {
|
||||
@@ -253,7 +271,9 @@ EcmaVM::~EcmaVM()
|
||||
ClearBufferData();
|
||||
|
||||
if (gcStats_ != nullptr) {
|
||||
gcStats_->PrintStatisticResult();
|
||||
#if ECMASCRIPT_ENABLE_GC_LOG
|
||||
gcStats_->PrintStatisticResult(true);
|
||||
#endif
|
||||
chunk_.Delete(gcStats_);
|
||||
gcStats_ = nullptr;
|
||||
}
|
||||
@@ -264,9 +284,6 @@ EcmaVM::~EcmaVM()
|
||||
heap_ = nullptr;
|
||||
}
|
||||
|
||||
delete propertiesCache_;
|
||||
propertiesCache_ = nullptr;
|
||||
|
||||
delete regExpParserCache_;
|
||||
regExpParserCache_ = nullptr;
|
||||
|
||||
@@ -449,7 +466,15 @@ Expected<int, Runtime::Error> EcmaVM::InvokeEcmaEntrypoint(const panda_file::Fil
|
||||
|
||||
InternalCallParams *params = thread_->GetInternalCallParams();
|
||||
params->MakeArgList(*jsargs);
|
||||
panda::ecmascript::InvokeJsFunction(thread_, func, global, newTarget, params);
|
||||
JSRuntimeOptions options = this->GetJSOptions();
|
||||
if (options.IsEnableCpuProfiler()) {
|
||||
CpuProfiler *profiler = CpuProfiler::GetInstance();
|
||||
profiler->CpuProfiler::StartCpuProfiler(this);
|
||||
panda::ecmascript::InvokeJsFunction(thread_, func, global, newTarget, params);
|
||||
profiler->CpuProfiler::StopCpuProfiler();
|
||||
} else {
|
||||
panda::ecmascript::InvokeJsFunction(thread_, func, global, newTarget, params);
|
||||
}
|
||||
if (!thread_->HasPendingException()) {
|
||||
job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
|
||||
}
|
||||
@@ -536,10 +561,6 @@ void EcmaVM::PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo)
|
||||
|
||||
void EcmaVM::ProcessReferences(const WeakRootVisitor &v0)
|
||||
{
|
||||
if (propertiesCache_ != nullptr) {
|
||||
propertiesCache_->Clear();
|
||||
}
|
||||
|
||||
if (regExpParserCache_ != nullptr) {
|
||||
regExpParserCache_->Clear();
|
||||
}
|
||||
|
||||
+69
-11
@@ -32,6 +32,7 @@
|
||||
#include "ecmascript/mem/heap.h"
|
||||
#include "ecmascript/mem/heap_roots.h"
|
||||
#include "ecmascript/mem/space.h"
|
||||
#include "ecmascript/platform/task.h"
|
||||
#include "ecmascript/snapshot/mem/snapshot_serialize.h"
|
||||
#include "ecmascript/tooling/pt_js_extractor.h"
|
||||
#include "include/panda_vm.h"
|
||||
@@ -47,14 +48,15 @@ class File;
|
||||
namespace ecmascript {
|
||||
class GlobalEnv;
|
||||
class ObjectFactory;
|
||||
class PropertiesCache;
|
||||
class RegExpParserCache;
|
||||
class EcmaRuntimeStat;
|
||||
class EcmaHeapManager;
|
||||
class Heap;
|
||||
class HeapTracker;
|
||||
class Program;
|
||||
|
||||
class RegExpExecResultCache;
|
||||
class JSPromise;
|
||||
enum class PromiseRejectionEvent : uint32_t;
|
||||
namespace job {
|
||||
class MicroJobQueue;
|
||||
} // namespace job
|
||||
@@ -66,6 +68,12 @@ class JSFunction;
|
||||
class Program;
|
||||
class ModuleManager;
|
||||
class EcmaModule;
|
||||
using HostPromiseRejectionTracker = void (*)(const EcmaVM* vm,
|
||||
const JSHandle<JSPromise> promise,
|
||||
const JSHandle<JSTaggedValue> reason,
|
||||
const PromiseRejectionEvent operation,
|
||||
void* data);
|
||||
using PromiseRejectCallback = void (*)(void* info);
|
||||
|
||||
class EcmaVM : public PandaVM {
|
||||
using PtJSExtractor = tooling::ecmascript::PtJSExtractor;
|
||||
@@ -227,11 +235,6 @@ public:
|
||||
|
||||
bool ExecutePromisePendingJob() const;
|
||||
|
||||
PropertiesCache *GetPropertiesCache() const
|
||||
{
|
||||
return propertiesCache_;
|
||||
}
|
||||
|
||||
RegExpParserCache *GetRegExpParserCache() const
|
||||
{
|
||||
ASSERT(regExpParserCache_ != nullptr);
|
||||
@@ -249,9 +252,8 @@ public:
|
||||
JSThread *GetJSThread() const
|
||||
{
|
||||
#if defined(ECMASCRIPT_ENABLE_THREAD_CHECK) && ECMASCRIPT_ENABLE_THREAD_CHECK
|
||||
ThreadPool *pool = GetHeap()->GetThreadPool();
|
||||
// Exclude GC thread
|
||||
if (!pool->IsInThreadPool(std::this_thread::get_id()) &&
|
||||
if (!Platform::GetCurrentPlatform()->IsInThreadPool(std::this_thread::get_id()) &&
|
||||
thread_->GetThreadId() != JSThread::GetCurrentThreadId()) {
|
||||
LOG(FATAL, RUNTIME) << "Fatal: ecma_vm cannot run in multi-thread!";
|
||||
}
|
||||
@@ -338,16 +340,54 @@ public:
|
||||
}
|
||||
|
||||
void SetupRegExpResultCache();
|
||||
JSHandle<JSTaggedValue> GetRegExpCache()
|
||||
|
||||
JSHandle<JSTaggedValue> GetRegExpCache() const
|
||||
{
|
||||
return JSHandle<JSTaggedValue>(reinterpret_cast<uintptr_t>(®expCache_));
|
||||
}
|
||||
|
||||
void SetRegExpCache(JSTaggedValue newCache)
|
||||
{
|
||||
regexpCache_ = newCache;
|
||||
}
|
||||
|
||||
RuntimeNotificationManager *GetNotificationManager() const
|
||||
{
|
||||
return notificationManager_;
|
||||
}
|
||||
|
||||
void SetEnableForceGC(bool enable)
|
||||
{
|
||||
options_.SetEnableForceGC(enable);
|
||||
}
|
||||
|
||||
void SetData(void* data)
|
||||
{
|
||||
data_ = data;
|
||||
}
|
||||
|
||||
void SetPromiseRejectCallback(PromiseRejectCallback cb)
|
||||
{
|
||||
promiseRejectCallback_ = cb;
|
||||
}
|
||||
|
||||
PromiseRejectCallback GetPromiseRejectCallback() const
|
||||
{
|
||||
return promiseRejectCallback_;
|
||||
}
|
||||
|
||||
void SetHostPromiseRejectionTracker(HostPromiseRejectionTracker cb)
|
||||
{
|
||||
hostPromiseRejectionTracker_ = cb;
|
||||
}
|
||||
|
||||
void PromiseRejectionTracker(const JSHandle<JSPromise> &promise,
|
||||
const JSHandle<JSTaggedValue> &reason, const PromiseRejectionEvent operation)
|
||||
{
|
||||
if (hostPromiseRejectionTracker_ != nullptr) {
|
||||
hostPromiseRejectionTracker_(this, promise, reason, operation, data_);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
bool CheckEntrypointSignature([[maybe_unused]] Method *entrypoint) override
|
||||
{
|
||||
@@ -362,6 +402,21 @@ protected:
|
||||
void PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t THREAD_SLEEP_TIME = 16 * 1000;
|
||||
static constexpr uint32_t THREAD_SLEEP_COUNT = 100;
|
||||
class TrimNewSpaceLimitTask : public Task {
|
||||
public:
|
||||
explicit TrimNewSpaceLimitTask(Heap *heap) : heap_(heap) {};
|
||||
~TrimNewSpaceLimitTask() override = default;
|
||||
bool Run(uint32_t threadIndex) override;
|
||||
|
||||
NO_COPY_SEMANTIC(TrimNewSpaceLimitTask);
|
||||
NO_MOVE_SEMANTIC(TrimNewSpaceLimitTask);
|
||||
|
||||
private:
|
||||
Heap *heap_;
|
||||
};
|
||||
|
||||
void AddPandaFile(const panda_file::File *pf, bool isModule);
|
||||
void SetProgram(Program *program, const panda_file::File *pf);
|
||||
bool IsFrameworkPandaFile(std::string_view filename) const;
|
||||
@@ -409,7 +464,6 @@ private:
|
||||
JSThread *thread_{nullptr};
|
||||
|
||||
// init EcmaVM Initialize
|
||||
PropertiesCache *propertiesCache_{nullptr};
|
||||
RegExpParserCache *regExpParserCache_{nullptr};
|
||||
Heap *heap_{nullptr};
|
||||
ObjectFactory *factory_{nullptr};
|
||||
@@ -432,6 +486,10 @@ private:
|
||||
CVector<JSNativePointer *> arrayBufferDataList_;
|
||||
CVector<std::tuple<Program *, const panda_file::File *, bool>> pandaFileWithProgram_;
|
||||
|
||||
PromiseRejectCallback promiseRejectCallback_ {nullptr};
|
||||
HostPromiseRejectionTracker hostPromiseRejectionTracker_ {nullptr};
|
||||
void* data_ {nullptr};
|
||||
|
||||
friend class SnapShotSerialize;
|
||||
friend class ObjectFactory;
|
||||
friend class ValueSerializer;
|
||||
|
||||
Regular → Executable
+83
-39
@@ -22,35 +22,40 @@
|
||||
// Frame Layout
|
||||
// Interpreter Frame(alias **iframe** ) Layout as follow:
|
||||
// ```
|
||||
// +---------------------------------+--------------------+
|
||||
// | argv[n-1] | ^
|
||||
// +----------------------------------+-------------------+
|
||||
// | argv[n-1] | ^
|
||||
// |----------------------------------| |
|
||||
// | ........ | |
|
||||
// | argv[0] | |
|
||||
// | ...... | |
|
||||
// |----------------------------------| |
|
||||
// | thisArg | |
|
||||
// | thisArg [maybe not exist] | |
|
||||
// |----------------------------------| |
|
||||
// | newTarget | |
|
||||
// | newTarget [maybe not exist] | |
|
||||
// |----------------------------------| |
|
||||
// | callTarget | |
|
||||
// +----------------------------------+--------+ |
|
||||
// | FrameType | ^ interpreter frame
|
||||
// | callTarget [deleted] | |
|
||||
// |----------------------------------| |
|
||||
// | ...... | |
|
||||
// |----------------------------------| |
|
||||
// | Vregs [not exist in native] | |
|
||||
// +----------------------------------+--------+ interpreter frame
|
||||
// | base.frameType | ^ |
|
||||
// |----------------------------------| | |
|
||||
// | pre(pre stack pointer) | | |
|
||||
// | base.prev(pre stack pointer) | | |
|
||||
// |----------------------------------| | |
|
||||
// | numActualArgs | | |
|
||||
// | numActualArgs [deleted] | | |
|
||||
// |----------------------------------| | |
|
||||
// | env | | |
|
||||
// | env | | |
|
||||
// |----------------------------------| | |
|
||||
// | acc | FrameState |
|
||||
// | acc | | |
|
||||
// |----------------------------------| FrameState |
|
||||
// | profileTypeInfo | | |
|
||||
// |----------------------------------| | |
|
||||
// | constantpool | | |
|
||||
// | constantpool | | |
|
||||
// |----------------------------------| | |
|
||||
// | method | | |
|
||||
// | method [changed to function] | | |
|
||||
// |----------------------------------| | |
|
||||
// | sp(current stack point) | | |
|
||||
// | sp(current stack point) | | |
|
||||
// |----------------------------------| | |
|
||||
// | pc(bytecode addr) | v v
|
||||
// | pc(bytecode addr) | v v
|
||||
// +----------------------------------+--------+----------+
|
||||
// ```
|
||||
// address space grow from high address to low address.we add new field **FrameType** ,
|
||||
@@ -73,13 +78,13 @@
|
||||
|
||||
// ```
|
||||
// +---------------------------------------------------+
|
||||
// | parameter i | ^
|
||||
// | parameter n | ^
|
||||
// |- - - - - - - - - -- | |
|
||||
// | parameter n-2 | Caller frame
|
||||
// | parameter n-1 | Caller frame
|
||||
// | ... | comply c-abi
|
||||
// | parameter n-1 | paramters push to stack from left to right
|
||||
// | parameter n-2 | paramters push to stack from left to right
|
||||
// |- - - - - - - - - | i-n th prameter spill to slot
|
||||
// | parameter n | v
|
||||
// | parameter i | v
|
||||
// +--------------------------+------------------------+
|
||||
// | return addr | ^ ^
|
||||
// |- - - - - - - - - | | |
|
||||
@@ -152,35 +157,36 @@
|
||||
|
||||
// Frame Layout as follow:
|
||||
// ```
|
||||
// +---------------------------------+--------------------+
|
||||
// | argv[n-1] | ^
|
||||
// +----------------------------------+-------------------+
|
||||
// | argv[n-1] | ^
|
||||
// |----------------------------------| |
|
||||
// | ........ | |
|
||||
// | argv[0] | |
|
||||
// | ...... | |
|
||||
// |----------------------------------| |
|
||||
// | thisArg | |
|
||||
// | thisArg [maybe not exist] | |
|
||||
// |----------------------------------| |
|
||||
// | newTarget | |
|
||||
// | newTarget [maybe not exist] | |
|
||||
// |----------------------------------| |
|
||||
// | callTarget | |
|
||||
// +----------------------------------+--------+ |
|
||||
// | FrameType | ^ foo's frame
|
||||
// | ...... | |
|
||||
// |----------------------------------| |
|
||||
// | Vregs | |
|
||||
// +----------------------------------+--------+ foo's frame
|
||||
// | base.frameType | ^ |
|
||||
// |----------------------------------| | |
|
||||
// | pre(pre stack pointer) | | |
|
||||
// | base.prev(pre stack pointer) | | |
|
||||
// |----------------------------------| | |
|
||||
// | numActualArgs | | |
|
||||
// | env | | |
|
||||
// |----------------------------------| | |
|
||||
// | env | | |
|
||||
// | acc | | |
|
||||
// |----------------------------------| | |
|
||||
// | acc | FrameState |
|
||||
// | profileTypeInfo | FrameState |
|
||||
// |----------------------------------| | |
|
||||
// | constantpool | | |
|
||||
// | constantpool | | |
|
||||
// |----------------------------------| | |
|
||||
// | method | | |
|
||||
// | function | | |
|
||||
// |----------------------------------| | |
|
||||
// | sp(current stack point) | | |
|
||||
// | sp(current stack point) | | |
|
||||
// |----------------------------------| | |
|
||||
// | pc(bytecode addr) | v v
|
||||
// | pc(bytecode addr) | v v
|
||||
// +----------------------------------+--------+----------+
|
||||
// | ............. |
|
||||
// +--------------------------+---------------------------+
|
||||
@@ -221,7 +227,21 @@
|
||||
#define GET_CURRETN_FP(fp) asm("mov %%rbp, %0" : "=rm" (fp))
|
||||
#define POINTER_CAST(fp, type) static_cast<type>(static_cast<void *>(fp)
|
||||
#define GET_PREV_FP(fp) reinterpret_cast<uintptr_t *>(*(fp))
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef PANDA_TARGET_ARM64
|
||||
#define GET_CURRETN_FP(fp) asm("mov %0, x29" : "=r" (fp))
|
||||
#define POINTER_CAST(fp, type) static_cast<type>(static_cast<void *>(fp))
|
||||
#define GET_PREV_FP(fp) reinterpret_cast<uintptr_t *>(*(POINTER_CAST(fp, uintptr_t *)))
|
||||
#endif
|
||||
|
||||
#ifdef PANDA_TARGET_ARM32
|
||||
#define GET_CURRETN_FP(fp) asm("mov %0, r11" : "=r" (fp))
|
||||
#define POINTER_CAST(fp, type) static_cast<type>(static_cast<void *>(fp))
|
||||
#define GET_PREV_FP(fp) reinterpret_cast<uintptr_t *>(*(POINTER_CAST(fp, uintptr_t *)))
|
||||
#endif
|
||||
|
||||
#if !defined(PANDA_TARGET_AMD64) && !defined(PANDA_TARGET_ARM64) && !defined(PANDA_TARGET_ARM32)
|
||||
#define GET_CURRETN_FP(fp)
|
||||
#define POINTER_CAST(fp, type) static_cast<type>(static_cast<void *>(fp))
|
||||
#define GET_PREV_FP(fp) reinterpret_cast<uintptr_t *>(*(POINTER_CAST(fp, uintptr_t *)))
|
||||
@@ -264,6 +284,30 @@ public:
|
||||
class FrameConst {
|
||||
public:
|
||||
static constexpr size_t FRAME_TYPE_OFFSET = -sizeof(uintptr_t);
|
||||
#ifdef PANDA_TARGET_AMD64
|
||||
static constexpr int SP_DWARF_REG_NUM = 7;
|
||||
static constexpr int FP_DWARF_REG_NUM = 6;
|
||||
static constexpr int SP_OFFSET = 2;
|
||||
#else
|
||||
#ifdef PANDA_TARGET_ARM64
|
||||
static constexpr int SP_DWARF_REG_NUM = 31; /* x31 */
|
||||
static constexpr int FP_DWARF_REG_NUM = 29; /* x29 */
|
||||
static constexpr int SP_OFFSET = -3;
|
||||
#else
|
||||
#ifdef PANDA_TARGET_ARM32
|
||||
static constexpr int SP_DWARF_REG_NUM = 13;
|
||||
static constexpr int FP_DWARF_REG_NUM = 11;
|
||||
static constexpr int SP_OFFSET = 0;
|
||||
#else
|
||||
static constexpr int SP_DWARF_REG_NUM = 0;
|
||||
static constexpr int FP_DWARF_REG_NUM = 0;
|
||||
static constexpr int SP_OFFSET = 0;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
static constexpr int AARCH64_SLOT_SIZE = 8;
|
||||
static constexpr int AMD64_SLOT_SIZE = 8;
|
||||
static constexpr int ARM32_SLOT_SIZE = 4;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_FRAMES_H
|
||||
|
||||
@@ -454,6 +454,7 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread)
|
||||
SetConstant(ConstantIndex::INPUT_INDEX, factory->NewFromCanBeCompressString("input").GetTaggedValue());
|
||||
SetConstant(ConstantIndex::UNICODE_INDEX, factory->NewFromCanBeCompressString("unicode").GetTaggedValue());
|
||||
SetConstant(ConstantIndex::ZERO_INDEX, factory->NewFromCanBeCompressString("0").GetTaggedValue());
|
||||
SetConstant(ConstantIndex::VALUES_INDEX, factory->NewFromCanBeCompressString("values").GetTaggedValue());
|
||||
|
||||
auto accessor = factory->NewInternalAccessor(reinterpret_cast<void *>(JSFunction::PrototypeSetter),
|
||||
reinterpret_cast<void *>(JSFunction::PrototypeGetter));
|
||||
|
||||
@@ -280,6 +280,7 @@ class JSThread;
|
||||
V(JSTaggedValue, Iso8601String, ISO8601_INDEX, iso8601) \
|
||||
V(JSTaggedValue, GregoryString, GREGORY_INDEX, gregory) \
|
||||
V(JSTaggedValue, EthioaaString, ETHIOAA_INDEX, ethioaa) \
|
||||
V(JSTaggedValue, ValuesString, VALUES_INDEX, values) \
|
||||
/* for regexp. */ \
|
||||
V(JSTaggedValue, ExecString, EXEC_INDEX, exec) \
|
||||
V(JSTaggedValue, LastIndexString, LAST_INDEX_INDEX, lastIndex) \
|
||||
|
||||
@@ -162,7 +162,7 @@ HeapSnapShot *HeapProfiler::MakeHeapSnapShot(JSThread *thread, SampleType sample
|
||||
{
|
||||
LOG(ERROR, RUNTIME) << "HeapProfiler::MakeHeapSnapShot";
|
||||
DISALLOW_GARBAGE_COLLECTION;
|
||||
heap_->GetSweeper()->EnsureAllTaskFinish();
|
||||
heap_->GetSweeper()->EnsureAllTaskFinished();
|
||||
switch (sampleType) {
|
||||
case SampleType::ONE_SHOT: {
|
||||
auto *snapShot =
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
#include "ecmascript/mem/heap.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
void HeapProfilerInterface::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath, bool isVmMode)
|
||||
void HeapProfilerInterface::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat,
|
||||
const CString &filePath, bool isVmMode)
|
||||
{
|
||||
LOG(ERROR, RUNTIME) << "HeapProfilerInterface::DumpHeapSnapshot";
|
||||
const Heap *heap = thread->GetEcmaVM()->GetHeap();
|
||||
@@ -39,7 +40,7 @@ HeapProfilerInterface *HeapProfilerInterface::CreateHeapProfiler(JSThread *threa
|
||||
return hprof;
|
||||
}
|
||||
|
||||
void HeapProfilerInterface::Destory(JSThread *thread, HeapProfilerInterface *heapProfiler)
|
||||
void HeapProfilerInterface::Destroy(JSThread *thread, HeapProfilerInterface *heapProfiler)
|
||||
{
|
||||
const Heap *heap = thread->GetEcmaVM()->GetHeap();
|
||||
const_cast<RegionFactory *>(heap->GetRegionFactory())->Delete(heapProfiler);
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
const CString &filePath, bool isVmMode = true);
|
||||
|
||||
static HeapProfilerInterface *CreateHeapProfiler(JSThread *thread);
|
||||
static void Destory(JSThread *thread, HeapProfilerInterface *heapProfiler);
|
||||
static void Destroy(JSThread *thread, HeapProfilerInterface *heapProfiler);
|
||||
|
||||
HeapProfilerInterface() = default;
|
||||
virtual ~HeapProfilerInterface() = default;
|
||||
|
||||
@@ -410,14 +410,14 @@ Node *HeapSnapShot::GenerateNode(JSThread *thread, JSTaggedValue entry, int sequ
|
||||
if (entry.IsString()) {
|
||||
node = GenerateStringNode(entry, sequenceId);
|
||||
if (node == nullptr) {
|
||||
LOG(ERROR, RUNTIME) << "string node nullptr";
|
||||
LOG(DEBUG, RUNTIME) << "string node nullptr";
|
||||
}
|
||||
}
|
||||
TaggedObject *obj = entry.GetTaggedObject();
|
||||
auto *baseClass = obj->GetClass();
|
||||
if (baseClass != nullptr) {
|
||||
node = Node::NewNode(heap_, sequenceId, nodeCount_, GenerateNodeName(thread, obj), GenerateNodeType(obj),
|
||||
obj->GetObjectSize(), obj);
|
||||
obj->GetClass()->SizeFromJSHClass(obj), obj);
|
||||
Node *existNode = entryMap_.FindOrInsertNode(node); // Fast Index
|
||||
if (existNode == node) {
|
||||
if (sequenceId == sequenceId_ + SEQ_STEP) {
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
void SetUp() override
|
||||
{
|
||||
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
|
||||
EcmaVM::Cast(instance)->GetFactory()->SetTriggerGc(false);
|
||||
EcmaVM::Cast(instance)->SetEnableForceGC(false);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -85,7 +85,7 @@ HWTEST_F_L0(HeapTrackerTest, HeapTracker)
|
||||
outputString.clear();
|
||||
|
||||
heapProfile->StopHeapTracking(thread, DumpFormat::JSON, fileName.c_str());
|
||||
HeapProfilerInterface::Destory(thread, heapProfile);
|
||||
HeapProfilerInterface::Destroy(thread, heapProfile);
|
||||
|
||||
// Check
|
||||
fstream inputStream(fileName, std::ios::in);
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
#include "ecmascript/hprof/heap_snapshot_json_serializer.h"
|
||||
#include "ecmascript/hprof/string_hashmap.h"
|
||||
#include "ecmascript/ic/ic_handler.h"
|
||||
#include "ecmascript/ic/proto_change_details.h"
|
||||
#include "ecmascript/ic/property_box.h"
|
||||
#include "ecmascript/ic/proto_change_details.h"
|
||||
#include "ecmascript/jobs/micro_job_queue.h"
|
||||
#include "ecmascript/jobs/pending_job.h"
|
||||
#include "ecmascript/js_arguments.h"
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_IC_IC_BINARY_OP_INL_H_
|
||||
#define ECMASCRIPT_IC_IC_BINARY_OP_INL_H_
|
||||
|
||||
#include "ic_binary_op.h"
|
||||
#include "ecmascript/ic/proto_change_details.h"
|
||||
#include "ecmascript/interpreter/interpreter-inl.h"
|
||||
#include "ecmascript/interpreter/slow_runtime_stub.h"
|
||||
#include "ecmascript/js_array.h"
|
||||
#include "ecmascript/js_handle.h"
|
||||
#include "ecmascript/js_tagged_value-inl.h"
|
||||
#include "ecmascript/napi/include/jsnapi.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
JSTaggedValue ICBinaryOP::AddWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, TryAddWithIC);
|
||||
BinaryType addType = static_cast<BinaryType>(argType.GetInt());
|
||||
switch (addType) {
|
||||
// Support cases, such as: int + double, int + int, double + double
|
||||
case BinaryType::NUMBER: {
|
||||
double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble();
|
||||
double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble();
|
||||
double ret = a0Double + a1Double;
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
// Support cases, such as: number + null, undefined + null, boolean + number, etc.
|
||||
case BinaryType::NUMBER_GEN: {
|
||||
JSHandle<JSTaggedValue> leftValue(thread, left);
|
||||
JSHandle<JSTaggedValue> rightValue(thread, right);
|
||||
JSHandle<JSTaggedValue> primitiveA0(thread, JSTaggedValue::ToPrimitive(thread, leftValue));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSTaggedValue> primitiveA1(thread, JSTaggedValue::ToPrimitive(thread, rightValue));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
JSTaggedNumber taggedValueA0 = JSTaggedValue::ToNumber(thread, primitiveA0);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSTaggedNumber taggedValueA1 = JSTaggedValue::ToNumber(thread, primitiveA1);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
double a0Double = taggedValueA0.GetNumber();
|
||||
double a1Double = taggedValueA1.GetNumber();
|
||||
return JSTaggedValue(a0Double + a1Double);
|
||||
}
|
||||
// Support case: string + string.
|
||||
case BinaryType::STRING: {
|
||||
JSHandle<EcmaString> stringA0 = JSHandle<EcmaString>(JSHandle<JSTaggedValue>(thread, left));
|
||||
JSHandle<EcmaString> stringA1 = JSHandle<EcmaString>(JSHandle<JSTaggedValue>(thread, right));
|
||||
EcmaString *ret = EcmaString::Concat(stringA0, stringA1, ecma_vm);
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
// Support cases, such as: string + null, string + object, string + boolean, string + number, etc.
|
||||
case BinaryType::STRING_GEN: {
|
||||
JSHandle<JSTaggedValue> leftValue(thread, left);
|
||||
JSHandle<JSTaggedValue> rightValue(thread, right);
|
||||
if (left.IsString()) {
|
||||
JSHandle<EcmaString> stringA0 = JSHandle<EcmaString>(leftValue);
|
||||
JSHandle<EcmaString> stringA1 = JSTaggedValue::ToString(thread, rightValue);
|
||||
EcmaString *ret = EcmaString::Concat(stringA0, stringA1, ecma_vm);
|
||||
return JSTaggedValue(ret);
|
||||
} else {
|
||||
JSHandle<EcmaString> stringA0 = JSTaggedValue::ToString(thread, leftValue);
|
||||
JSHandle<EcmaString> stringA1 = JSHandle<EcmaString>(rightValue);
|
||||
EcmaString *ret = EcmaString::Concat(stringA0, stringA1, ecma_vm);
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
}
|
||||
// Some special cases, such as: object + undefined, object + boolean, etc.
|
||||
case BinaryType::GENERIC: {
|
||||
JSTaggedValue res = SlowRuntimeStub::Add2Dyn(thread, ecma_vm, left, right);
|
||||
return res;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::SubWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, TrySubWithIC);
|
||||
BinaryType subType = static_cast<BinaryType>(argType.GetInt());
|
||||
switch (subType) {
|
||||
// Support int or number
|
||||
case BinaryType::NUMBER: {
|
||||
double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble();
|
||||
double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble();
|
||||
double ret = a0Double - a1Double;
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
// Support cases, such as: string like '2333', boolean, null
|
||||
case BinaryType::GENERIC: {
|
||||
JSHandle<JSTaggedValue> leftValue(thread, left);
|
||||
JSHandle<JSTaggedValue> rightValue(thread, right);
|
||||
JSTaggedNumber number0 = JSTaggedValue::ToNumber(thread, leftValue);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSTaggedNumber number1 = JSTaggedValue::ToNumber(thread, rightValue);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
auto ret = number0 - number1;
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
case BinaryType::NUMBER_GEN:
|
||||
case BinaryType::STRING:
|
||||
case BinaryType::STRING_GEN:
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::MulWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, TryMulWithIC);
|
||||
BinaryType mulType = static_cast<BinaryType>(argType.GetInt());
|
||||
switch (mulType) {
|
||||
// Support int or number
|
||||
case BinaryType::NUMBER: {
|
||||
return JSTaggedValue(left.GetNumber() * right.GetNumber());
|
||||
}
|
||||
// Support cases, such as: string like '2333', boolean, null
|
||||
case BinaryType::GENERIC: {
|
||||
JSHandle<JSTaggedValue> leftValue(thread, left);
|
||||
JSHandle<JSTaggedValue> rightValue(thread, right);
|
||||
// 6. Let lnum be ToNumber(leftValue).
|
||||
JSTaggedNumber primitiveA = JSTaggedValue::ToNumber(thread, leftValue);
|
||||
// 7. ReturnIfAbrupt(lnum).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// 8. Let rnum be ToNumber(rightValue).
|
||||
JSTaggedNumber primitiveB = JSTaggedValue::ToNumber(thread, rightValue);
|
||||
// 9. ReturnIfAbrupt(rnum).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// 12.6.3.1 Applying the * Operator
|
||||
return primitiveA * primitiveB;
|
||||
}
|
||||
case BinaryType::NUMBER_GEN:
|
||||
case BinaryType::STRING:
|
||||
case BinaryType::STRING_GEN:
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::DivWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, TryDivWithIC);
|
||||
BinaryType divType = static_cast<BinaryType>(argType.GetInt());
|
||||
switch (divType) {
|
||||
// Support int or number
|
||||
case BinaryType::NUMBER: {
|
||||
double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
|
||||
double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
|
||||
if (UNLIKELY(dRight == 0.0)) {
|
||||
if (dLeft == 0.0 || std::isnan(dLeft)) {
|
||||
return JSTaggedValue(base::NAN_VALUE);
|
||||
}
|
||||
uint64_t flagBit = ((bit_cast<uint64_t>(dLeft)) ^ (bit_cast<uint64_t>(dRight))) &
|
||||
base::DOUBLE_SIGN_MASK;
|
||||
return JSTaggedValue(bit_cast<double>(flagBit ^ (bit_cast<uint64_t>(base::POSITIVE_INFINITY))));
|
||||
}
|
||||
return JSTaggedValue(dLeft / dRight);
|
||||
}
|
||||
// Support special cases, such as: string like '2333', boolean, null
|
||||
case BinaryType::GENERIC: {
|
||||
auto res = SlowRuntimeStub::Div2Dyn(thread, left, right);
|
||||
return res;
|
||||
}
|
||||
case BinaryType::NUMBER_GEN:
|
||||
case BinaryType::STRING:
|
||||
case BinaryType::STRING_GEN:
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::ModWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, TryModWithIC);
|
||||
BinaryType modType = static_cast<BinaryType>(argType.GetInt());
|
||||
switch (modType) {
|
||||
// Support int or number
|
||||
case BinaryType::NUMBER: {
|
||||
double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
|
||||
double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
|
||||
if (dRight == 0.0 || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) {
|
||||
return JSTaggedValue(base::NAN_VALUE);
|
||||
}
|
||||
if (dLeft == 0.0 || std::isinf(dRight)) {
|
||||
return JSTaggedValue(dLeft);
|
||||
}
|
||||
return JSTaggedValue(std::fmod(dLeft, dRight));
|
||||
}
|
||||
// Support special cases, such as: string like '2333', boolean, null
|
||||
case BinaryType::GENERIC: {
|
||||
JSHandle<JSTaggedValue> leftValue(thread, left);
|
||||
JSHandle<JSTaggedValue> rightValue(thread, right);
|
||||
JSTaggedNumber leftNumber = JSTaggedValue::ToNumber(thread, leftValue);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
double dLeft = leftNumber.GetNumber();
|
||||
JSTaggedNumber rightNumber = JSTaggedValue::ToNumber(thread, rightValue);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
double dRight = rightNumber.GetNumber();
|
||||
// 12.6.3.3 Applying the % Operator
|
||||
if ((dRight == 0.0) || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) {
|
||||
return JSTaggedValue(base::NAN_VALUE);
|
||||
}
|
||||
if ((dLeft == 0.0) || std::isinf(dRight)) {
|
||||
return JSTaggedValue(dLeft);
|
||||
}
|
||||
return JSTaggedValue(std::fmod(dLeft, dRight));
|
||||
}
|
||||
case BinaryType::NUMBER_GEN:
|
||||
case BinaryType::STRING:
|
||||
case BinaryType::STRING_GEN:
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ICBinaryOP::GetBitOPDate(JSThread *thread, JSTaggedValue left, JSTaggedValue right,
|
||||
int32_t &opNumber0, int32_t &opNumber1, BinaryType opType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, GetBitOPDate);
|
||||
switch (opType) {
|
||||
case BinaryType::NUMBER: {
|
||||
opNumber0 =
|
||||
left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS);
|
||||
opNumber1 =
|
||||
right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS);
|
||||
break;
|
||||
}
|
||||
// Support special cases, such as: string like '2333', boolean, null
|
||||
case BinaryType::GENERIC: {
|
||||
JSHandle<JSTaggedValue> leftValue(thread, left);
|
||||
JSHandle<JSTaggedValue> rightValue(thread, right);
|
||||
JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread,
|
||||
leftValue.GetTaggedValue());
|
||||
JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread,
|
||||
rightValue.GetTaggedValue());
|
||||
opNumber0 = taggedNumber0.GetInt();
|
||||
opNumber1 = taggedNumber1.GetInt();
|
||||
break;
|
||||
}
|
||||
case BinaryType::NUMBER_GEN:
|
||||
case BinaryType::STRING:
|
||||
case BinaryType::STRING_GEN:
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::ShlWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, ShlWithTSType);
|
||||
BinaryType shlType = static_cast<BinaryType>(argType.GetInt());
|
||||
int32_t opNumber0;
|
||||
int32_t opNumber1;
|
||||
GetBitOPDate(thread, left, right, opNumber0, opNumber1, shlType);
|
||||
uint32_t shift =
|
||||
static_cast<uint32_t>(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
|
||||
using unsigned_type = std::make_unsigned_t<int32_t>;
|
||||
auto ret =
|
||||
static_cast<int32_t>(static_cast<unsigned_type>(opNumber0) << shift); // NOLINT(hicpp-signed-bitwise)
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::ShrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, ShrWithTSType);
|
||||
BinaryType shrType = static_cast<BinaryType>(argType.GetInt());
|
||||
int32_t opNumber0;
|
||||
int32_t opNumber1;
|
||||
GetBitOPDate(thread, left, right, opNumber0, opNumber1, shrType);
|
||||
uint32_t shift =
|
||||
static_cast<uint32_t>(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
|
||||
auto ret = static_cast<int32_t>(opNumber0 >> shift); // NOLINT(hicpp-signed-bitwise)
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::AshrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, AshrWithTSType);
|
||||
BinaryType ashrType = static_cast<BinaryType>(argType.GetInt());
|
||||
int32_t opNumber0;
|
||||
int32_t opNumber1;
|
||||
GetBitOPDate(thread, left, right, opNumber0, opNumber1, ashrType);
|
||||
uint32_t shift =
|
||||
static_cast<uint32_t>(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
|
||||
using unsigned_type = std::make_unsigned_t<uint32_t>;
|
||||
auto ret =
|
||||
static_cast<uint32_t>(static_cast<unsigned_type>(opNumber0) >> shift); // NOLINT(hicpp-signed-bitwise)
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::AndWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, AndWithTSType);
|
||||
BinaryType andType = static_cast<BinaryType>(argType.GetInt());
|
||||
int32_t opNumber0;
|
||||
int32_t opNumber1;
|
||||
GetBitOPDate(thread, left, right, opNumber0, opNumber1, andType);
|
||||
// NOLINT(hicpp-signed-bitwise)
|
||||
auto ret = static_cast<uint32_t>(opNumber0) & static_cast<uint32_t>(opNumber1);
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::OrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, OrWithTSType);
|
||||
BinaryType orType = static_cast<BinaryType>(argType.GetInt());
|
||||
int32_t opNumber0;
|
||||
int32_t opNumber1;
|
||||
GetBitOPDate(thread, left, right, opNumber0, opNumber1, orType);
|
||||
// NOLINT(hicpp-signed-bitwise)
|
||||
auto ret = static_cast<uint32_t>(opNumber0) | static_cast<uint32_t>(opNumber1);
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
|
||||
JSTaggedValue ICBinaryOP::XorWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, XorWithTSType);
|
||||
BinaryType xorType = static_cast<BinaryType>(argType.GetInt());
|
||||
int32_t opNumber0;
|
||||
int32_t opNumber1;
|
||||
GetBitOPDate(thread, left, right, opNumber0, opNumber1, xorType);
|
||||
// NOLINT(hicpp-signed-bitwise)
|
||||
auto ret = static_cast<uint32_t>(opNumber0) ^ static_cast<uint32_t>(opNumber1);
|
||||
return JSTaggedValue(ret);
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_IC_IC_BINARY_OP_INL_H_
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_IC_IC_BINARY_OP_H_
|
||||
#define ECMASCRIPT_IC_IC_BINARY_OP_H_
|
||||
|
||||
#include "ecmascript/js_tagged_value.h"
|
||||
#include "ecmascript/property_attributes.h"
|
||||
#include "ecmascript/ic/profile_type_info.h"
|
||||
#include "ecmascript/runtime_call_id.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
enum class BinaryType : uint8_t {
|
||||
NUMBER,
|
||||
NUMBER_GEN,
|
||||
STRING,
|
||||
STRING_GEN,
|
||||
GENERIC,
|
||||
};
|
||||
|
||||
class ICBinaryOP {
|
||||
public:
|
||||
static inline JSTaggedValue AddWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue SubWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue MulWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue DivWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue ModWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline void GetBitOPDate(JSThread *thread, JSTaggedValue left, JSTaggedValue right,
|
||||
int32_t &opNumber0, int32_t &opNumber1, BinaryType opType);
|
||||
static inline JSTaggedValue ShlWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue ShrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue AshrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue AndWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue OrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
static inline JSTaggedValue XorWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
|
||||
JSTaggedValue right, JSTaggedValue argType);
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // ECMASCRIPT_IC_IC_BINARY_OP_H_
|
||||
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* 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/ic/ic_compare_op.h"
|
||||
|
||||
#include "ecmascript/accessor_data.h"
|
||||
#include "ecmascript/base/error_helper.h"
|
||||
#include "ecmascript/base/number_helper.h"
|
||||
#include "ecmascript/base/string_helper.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "ecmascript/ecma_runtime_call_info.h"
|
||||
#include "ecmascript/ecma_string-inl.h"
|
||||
#include "ecmascript/js_hclass-inl.h"
|
||||
#include "ecmascript/js_object.h"
|
||||
#include "ecmascript/js_proxy.h"
|
||||
#include "ecmascript/js_symbol.h"
|
||||
#include "ecmascript/js_tagged_number.h"
|
||||
#include "ecmascript/js_tagged_value.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "ecmascript/mem/c_containers.h"
|
||||
#include "ecmascript/mem/tagged_object-inl.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/runtime_call_id.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
JSTaggedValue CompareOp::EqualWithIC(JSThread* thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, EqualWithIC);
|
||||
double leftDouble = 0;
|
||||
double rightDouble = 0;
|
||||
JSTaggedValue ret = JSTaggedValue::False();
|
||||
switch (operationType) {
|
||||
case CompareOpType::NUMBER_NUMBER: {
|
||||
leftDouble = left.GetNumber();
|
||||
rightDouble = right.GetNumber();
|
||||
ret = JSTaggedValue(JSTaggedValue::StrictNumberEquals(leftDouble, rightDouble));
|
||||
break;
|
||||
}
|
||||
case CompareOpType::STRING_NUMBER: {
|
||||
JSTaggedValue temp = left;
|
||||
left = right;
|
||||
right = temp;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case CompareOpType::NUMBER_STRING: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
rightDouble = JSTaggedValue::ToNumber(thread, rightHandle).GetNumber();
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False());
|
||||
leftDouble = leftHandle.GetTaggedValue().GetNumber();
|
||||
ret = JSTaggedValue(JSTaggedValue::StrictNumberEquals(leftDouble, rightDouble));
|
||||
break;
|
||||
}
|
||||
case CompareOpType::BOOLEAN_NUMBER: {
|
||||
JSTaggedValue temp = left;
|
||||
left = right;
|
||||
right = temp;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case CompareOpType::NUMBER_BOOLEAN: {
|
||||
leftDouble = left.GetNumber();
|
||||
if (right.GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
rightDouble = 1;
|
||||
}
|
||||
ret = JSTaggedValue(JSTaggedValue::StrictNumberEquals(leftDouble, rightDouble));
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_NUMBER: {
|
||||
JSTaggedValue temp = left;
|
||||
left = right;
|
||||
right = temp;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case CompareOpType::NUMBER_OBJ: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> rightPrimitive(thread, JSTaggedValue::ToPrimitive(thread, rightHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False());
|
||||
if (rightPrimitive->IsNumber()) {
|
||||
ret = EqualWithIC(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_NUMBER);
|
||||
} else if (rightPrimitive->IsString()) {
|
||||
ret = EqualWithIC(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_STRING);
|
||||
} else if (rightPrimitive->IsBoolean()) {
|
||||
ret = EqualWithIC(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::STRING_STRING: {
|
||||
bool result = EcmaString::StringsAreEqual(static_cast<EcmaString *>(left.GetTaggedObject()),
|
||||
static_cast<EcmaString *>(right.GetTaggedObject()));
|
||||
ret = result ? JSTaggedValue::True() : JSTaggedValue::False();
|
||||
break;
|
||||
}
|
||||
case CompareOpType::BOOLEAN_STRING: {
|
||||
JSTaggedValue temp = left;
|
||||
left = right;
|
||||
right = temp;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case CompareOpType::STRING_BOOLEAN: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
leftDouble = JSTaggedValue::ToNumber(thread, leftHandle).GetNumber();
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False());
|
||||
if (rightHandle.GetTaggedValue().GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
rightDouble = 1;
|
||||
}
|
||||
ret = JSTaggedValue(JSTaggedValue::StrictNumberEquals(leftDouble, rightDouble));
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_STRING: {
|
||||
JSTaggedValue temp = left;
|
||||
left = right;
|
||||
right = temp;
|
||||
[[fallthrough]];
|
||||
}
|
||||
case CompareOpType::STRING_OBJ: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> rightPrimitive(thread, JSTaggedValue::ToPrimitive(thread, rightHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False());
|
||||
if (rightPrimitive->IsNumber()) {
|
||||
ret = EqualWithIC(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_STRING);
|
||||
} else if (rightPrimitive->IsString()) {
|
||||
ret = EqualWithIC(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::STRING_STRING);
|
||||
} else if (rightPrimitive->IsBoolean()) {
|
||||
ret = EqualWithIC(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::BOOLEAN_BOOLEAN: {
|
||||
if (left.GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
leftDouble = 1;
|
||||
}
|
||||
if (right.GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
rightDouble = 1;
|
||||
}
|
||||
ret = JSTaggedValue(JSTaggedValue::StrictNumberEquals(leftDouble, rightDouble));
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_BOOLEAN: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> leftPrimitive(thread, JSTaggedValue::ToPrimitive(thread, leftHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False());
|
||||
if (leftPrimitive->IsNumber()) {
|
||||
ret = EqualWithIC(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::NUMBER_BOOLEAN);
|
||||
} else if (leftPrimitive->IsString()) {
|
||||
ret = EqualWithIC(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
} else if (leftPrimitive->IsBoolean()) {
|
||||
ret = EqualWithIC(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::BOOLEAN_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::BOOLEAN_OBJ: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> rightPrimitive(thread, JSTaggedValue::ToPrimitive(thread, rightHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False());
|
||||
if (rightPrimitive->IsNumber()) {
|
||||
ret = EqualWithIC(thread, rightPrimitive.GetTaggedValue(),
|
||||
leftHandle.GetTaggedValue(), CompareOpType::NUMBER_BOOLEAN);
|
||||
} else if (rightPrimitive->IsString()) {
|
||||
ret = EqualWithIC(thread, rightPrimitive.GetTaggedValue(),
|
||||
leftHandle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
} else if (rightPrimitive->IsBoolean()) {
|
||||
ret = EqualWithIC(thread, rightPrimitive.GetTaggedValue(),
|
||||
leftHandle.GetTaggedValue(), CompareOpType::BOOLEAN_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_OBJ: {
|
||||
// if same type, must call Type::StrictEqual()
|
||||
JSType xType = left.GetTaggedObject()->GetClass()->GetObjectType();
|
||||
JSType yType = right.GetTaggedObject()->GetClass()->GetObjectType();
|
||||
bool resultObj = false;
|
||||
if (xType == yType) {
|
||||
resultObj = JSTaggedValue::StrictEqual(thread, JSHandle<JSTaggedValue>(thread, left),
|
||||
JSHandle<JSTaggedValue>(thread, right));
|
||||
}
|
||||
ret = resultObj ? JSTaggedValue::True() : JSTaggedValue::False();
|
||||
break;
|
||||
}
|
||||
case CompareOpType::SYMBOL_SYMBOL: {
|
||||
ret = left == right ? JSTaggedValue::True() : JSTaggedValue::False();
|
||||
break;
|
||||
}
|
||||
case CompareOpType::NULL_NULL:
|
||||
case CompareOpType::NULL_UNDEFINED:
|
||||
case CompareOpType::UNDEFINED_UNDEFINED:
|
||||
case CompareOpType::UNDEFINED_NULL: {
|
||||
ret = JSTaggedValue::True();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = JSTaggedValue::False();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSTaggedValue CompareOp::NotEqualWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, NotEqualWithIC);
|
||||
JSTaggedValue res = EqualWithIC(thread, left, right, operationType);
|
||||
return res == JSTaggedValue::True() ? JSTaggedValue::False() : JSTaggedValue::True();
|
||||
}
|
||||
|
||||
ComparisonResult CompareOp::Compare(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, Compare);
|
||||
double leftDouble = 0;
|
||||
double rightDouble = 0;
|
||||
ComparisonResult ret = ComparisonResult::UNDEFINED;
|
||||
switch (operationType) {
|
||||
case CompareOpType::NUMBER_NUMBER: {
|
||||
leftDouble = left.IsInt() ? static_cast<double>(left.GetInt()) : left.GetDouble();
|
||||
rightDouble = right.IsInt() ? static_cast<double>(right.GetInt()) : right.GetDouble();
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
case CompareOpType::NUMBER_STRING: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
|
||||
rightDouble = JSTaggedValue::ToNumber(thread, rightHandle).GetNumber();
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
leftDouble = leftHandle.GetTaggedValue().GetNumber();
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
case CompareOpType::NUMBER_BOOLEAN: {
|
||||
leftDouble = left.GetNumber();
|
||||
if (right.GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
rightDouble = 1;
|
||||
}
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
case CompareOpType::NUMBER_OBJ: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> rightPrimitive(thread, JSTaggedValue::ToPrimitive(thread, rightHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (rightPrimitive->IsNumber()) {
|
||||
ret = Compare(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_NUMBER);
|
||||
} else if (rightPrimitive->IsString()) {
|
||||
ret = Compare(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_STRING);
|
||||
} else if (rightPrimitive->IsBoolean()) {
|
||||
ret = Compare(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::STRING_STRING: {
|
||||
auto xString = static_cast<EcmaString *>(left.GetTaggedObject());
|
||||
auto yString = static_cast<EcmaString *>(right.GetTaggedObject());
|
||||
int result = xString->Compare(yString);
|
||||
if (result < 0) {
|
||||
ret = ComparisonResult::LESS;
|
||||
} else if (result == 0) {
|
||||
ret = ComparisonResult::EQUAL;
|
||||
} else {
|
||||
ret = ComparisonResult::GREAT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::STRING_NUMBER: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
leftDouble = JSTaggedValue::ToNumber(thread, leftHandle).GetNumber();
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
rightDouble = rightHandle.GetTaggedValue().GetNumber();
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
case CompareOpType::STRING_BOOLEAN: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
leftDouble = JSTaggedValue::ToNumber(thread, leftHandle).GetNumber();
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (rightHandle.GetTaggedValue().GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
rightDouble = 1;
|
||||
}
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
case CompareOpType::STRING_OBJ: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> rightPrimitive(thread, JSTaggedValue::ToPrimitive(thread, rightHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (rightPrimitive->IsNumber()) {
|
||||
ret = Compare(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::NUMBER_STRING);
|
||||
} else if (rightPrimitive->IsString()) {
|
||||
ret = Compare(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::STRING_STRING);
|
||||
} else if (rightPrimitive->IsBoolean()) {
|
||||
ret = Compare(thread, leftHandle.GetTaggedValue(),
|
||||
rightPrimitive.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::BOOLEAN_BOOLEAN: {
|
||||
if (left.GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
leftDouble = 1;
|
||||
}
|
||||
if (right.GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
rightDouble = 1;
|
||||
}
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
|
||||
case CompareOpType::BOOLEAN_NUMBER: {
|
||||
if (left.GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
leftDouble = 1;
|
||||
}
|
||||
rightDouble = right.GetNumber();
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
|
||||
case CompareOpType::BOOLEAN_STRING: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
rightDouble = JSTaggedValue::ToNumber(thread, rightHandle).GetNumber();
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (leftHandle.GetTaggedValue().GetRawData() == JSTaggedValue::VALUE_TRUE) {
|
||||
leftDouble = 1;
|
||||
}
|
||||
ret = JSTaggedValue::StrictNumberCompare(leftDouble, rightDouble);
|
||||
break;
|
||||
}
|
||||
|
||||
case CompareOpType::BOOLEAN_OBJ: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> rightPrimitive(thread, JSTaggedValue::ToPrimitive(thread, rightHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (rightPrimitive->IsNumber()) {
|
||||
ret = Compare(thread, rightPrimitive.GetTaggedValue(),
|
||||
leftHandle.GetTaggedValue(), CompareOpType::NUMBER_BOOLEAN);
|
||||
} else if (rightPrimitive->IsString()) {
|
||||
ret = Compare(thread, rightPrimitive.GetTaggedValue(),
|
||||
leftHandle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
} else if (rightPrimitive->IsBoolean()) {
|
||||
ret = Compare(thread, rightPrimitive.GetTaggedValue(),
|
||||
leftHandle.GetTaggedValue(), CompareOpType::BOOLEAN_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_OBJ: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
ret = JSTaggedValue::Compare(thread, leftHandle, rightHandle);
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_NUMBER: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> leftPrimitive(thread, JSTaggedValue::ToPrimitive(thread, leftHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (leftPrimitive->IsNumber()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::NUMBER_NUMBER);
|
||||
} else if (leftPrimitive->IsString()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::STRING_NUMBER);
|
||||
} else if (leftPrimitive->IsBoolean()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::BOOLEAN_NUMBER);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_STRING: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> leftPrimitive(thread, JSTaggedValue::ToPrimitive(thread, leftHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (leftPrimitive->IsNumber()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::NUMBER_STRING);
|
||||
} else if (leftPrimitive->IsString()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::STRING_STRING);
|
||||
} else if (leftPrimitive->IsBoolean()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::BOOLEAN_STRING);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CompareOpType::OBJ_BOOLEAN: {
|
||||
JSHandle<JSTaggedValue> leftHandle(thread, left);
|
||||
JSHandle<JSTaggedValue> rightHandle(thread, right);
|
||||
JSHandle<JSTaggedValue> leftPrimitive(thread, JSTaggedValue::ToPrimitive(thread, leftHandle));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ComparisonResult::UNDEFINED);
|
||||
if (leftPrimitive->IsNumber()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::NUMBER_BOOLEAN);
|
||||
} else if (leftPrimitive->IsString()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
} else if (leftPrimitive->IsBoolean()) {
|
||||
ret = Compare(thread, leftPrimitive.GetTaggedValue(),
|
||||
rightHandle.GetTaggedValue(), CompareOpType::BOOLEAN_BOOLEAN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = ComparisonResult::UNDEFINED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSTaggedValue CompareOp::LessDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, NotEqualWithIC);
|
||||
bool ret = CompareOp::Compare(thread, left, right, operationType) == ComparisonResult::LESS;
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return (ret ? JSTaggedValue::True() : JSTaggedValue::False());
|
||||
}
|
||||
|
||||
JSTaggedValue CompareOp::LessEqDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, NotEqualWithIC);
|
||||
bool ret = CompareOp::Compare(thread, left, right, operationType) <= ComparisonResult::EQUAL;
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return (ret ? JSTaggedValue::True() : JSTaggedValue::False());
|
||||
}
|
||||
|
||||
JSTaggedValue CompareOp::GreaterDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, NotEqualWithIC);
|
||||
bool ret = CompareOp::Compare(thread, left, right, operationType) == ComparisonResult::GREAT;
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return (ret ? JSTaggedValue::True() : JSTaggedValue::False());
|
||||
}
|
||||
|
||||
JSTaggedValue CompareOp::GreaterEqDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, NotEqualWithIC);
|
||||
ComparisonResult comparison = CompareOp::Compare(thread, left, right, operationType);
|
||||
bool ret = (comparison == ComparisonResult::GREAT) || (comparison == ComparisonResult::EQUAL);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
return (ret ? JSTaggedValue::True() : JSTaggedValue::False());
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_IC_IC_COMPARE_H
|
||||
#define ECMASCRIPT_IC_IC_COMPARE_H
|
||||
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
enum class CompareOpType {
|
||||
NUMBER_NUMBER,
|
||||
NUMBER_STRING,
|
||||
NUMBER_BOOLEAN,
|
||||
NUMBER_OBJ,
|
||||
STRING_STRING,
|
||||
STRING_NUMBER,
|
||||
STRING_BOOLEAN,
|
||||
STRING_OBJ,
|
||||
BOOLEAN_BOOLEAN,
|
||||
BOOLEAN_NUMBER,
|
||||
BOOLEAN_STRING,
|
||||
BOOLEAN_OBJ,
|
||||
OBJ_OBJ,
|
||||
OBJ_NUMBER,
|
||||
OBJ_STRING,
|
||||
OBJ_BOOLEAN,
|
||||
SYMBOL_SYMBOL,
|
||||
NULL_NULL,
|
||||
NULL_UNDEFINED,
|
||||
UNDEFINED_UNDEFINED,
|
||||
UNDEFINED_NULL,
|
||||
UNDEFINED_BLLEAN,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
class CompareOp {
|
||||
public:
|
||||
|
||||
CompareOp() = default;
|
||||
~CompareOp() = default;
|
||||
|
||||
static JSTaggedValue EqualWithIC(JSThread* thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType);
|
||||
|
||||
static JSTaggedValue NotEqualWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType);
|
||||
|
||||
static ComparisonResult Compare(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType);
|
||||
|
||||
static JSTaggedValue LessDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType);
|
||||
|
||||
static JSTaggedValue LessEqDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType);
|
||||
|
||||
static JSTaggedValue GreaterDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType);
|
||||
|
||||
static JSTaggedValue GreaterEqDynWithIC(JSThread *thread, JSTaggedValue left,
|
||||
JSTaggedValue right, CompareOpType operationType);
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_IC_IC_COMPAREOP_H
|
||||
@@ -52,7 +52,7 @@ JSHandle<JSTaggedValue> LoadHandler::LoadProperty(const JSThread *thread, const
|
||||
if (op.IsInlinedProps()) {
|
||||
InlinedPropsBit::Set<uint32_t>(true, &handler);
|
||||
JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder());
|
||||
auto index = holder->GetPropertyInObjectIndex(op.GetIndex());
|
||||
auto index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
||||
OffsetBit::Set<uint32_t>(index, &handler);
|
||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler));
|
||||
}
|
||||
@@ -120,7 +120,7 @@ JSHandle<JSTaggedValue> StoreHandler::StoreProperty(const JSThread *thread, cons
|
||||
if (op.IsInlinedProps()) {
|
||||
InlinedPropsBit::Set<uint32_t>(true, &handler);
|
||||
JSHandle<JSObject> receiver = JSHandle<JSObject>::Cast(op.GetReceiver());
|
||||
auto index = receiver->GetPropertyInObjectIndex(op.GetIndex());
|
||||
auto index = receiver->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
||||
OffsetBit::Set<uint32_t>(index, &handler);
|
||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue(handler));
|
||||
}
|
||||
|
||||
@@ -88,7 +88,8 @@ JSTaggedValue ICRuntimeStub::CheckPolyHClass(JSTaggedValue cachedValue, JSHClass
|
||||
TaggedArray *array = TaggedArray::Cast(cachedValue.GetHeapObject());
|
||||
array_size_t length = array->GetLength();
|
||||
for (array_size_t i = 0; i < length; i += 2) { // 2 means one ic, two slot
|
||||
if (array->Get(i).GetWeakReferent() == hclass) {
|
||||
auto result = array->Get(i);
|
||||
if (result != JSTaggedValue::Undefined() && result.GetWeakReferent() == hclass) {
|
||||
return array->Get(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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/ic/invoke_cache.h"
|
||||
#include "ecmascript/interpreter/interpreter-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
// Build the infrastructure and wait for TS to invoke.
|
||||
bool InvokeCache::SetMonoConstuctCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
JSTaggedValue newTarget, JSTaggedValue initialHClass)
|
||||
{
|
||||
// only cache class constructor
|
||||
if (UNLIKELY(!newTarget.IsClassConstructor())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
profileTypeInfo->Set(thread, slotId, newTarget);
|
||||
profileTypeInfo->Set(thread, slotId + 1, initialHClass);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvokeCache::SetPolyConstuctCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
uint8_t length, JSTaggedValue newTargetArray,
|
||||
JSTaggedValue initialHClassArray)
|
||||
{
|
||||
ASSERT(length <= 4 && newTargetArray.IsTaggedArray() && initialHClassArray.IsTaggedArray());
|
||||
|
||||
JSHandle<TaggedArray> profileTypeInfoArr(thread, profileTypeInfo);
|
||||
JSHandle<TaggedArray> newTargetArr(thread, newTargetArray);
|
||||
JSHandle<TaggedArray> initialHClassArr(thread, initialHClassArray);
|
||||
|
||||
auto factory = thread->GetEcmaVM()->GetFactory();
|
||||
constexpr uint8_t step = 2;
|
||||
JSHandle<TaggedArray> newArray = factory->NewTaggedArray(length * step); // 2: newTarget and hclass
|
||||
|
||||
for (uint8_t index = 0; index < length; ++index) {
|
||||
ASSERT(newTargetArr->Get(index).IsClassConstructor());
|
||||
|
||||
newArray->Set(thread, index * step, newTargetArr->Get(index));
|
||||
newArray->Set(thread, index * step + 1, initialHClassArr->Get(index));
|
||||
}
|
||||
|
||||
profileTypeInfoArr->Set(thread, slotId, newArray);
|
||||
profileTypeInfoArr->Set(thread, slotId + 1, JSTaggedValue::Hole());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSTaggedValue InvokeCache::CheckPolyInvokeCache(JSTaggedValue cachedArray, JSTaggedValue func)
|
||||
{
|
||||
ASSERT(cachedArray.IsTaggedArray());
|
||||
TaggedArray *array = TaggedArray::Cast(cachedArray.GetHeapObject());
|
||||
array_size_t length = array->GetLength();
|
||||
for (array_size_t index = 0; index < length; index += 2) { // 2: means one ic, two slot
|
||||
auto result = array->Get(index);
|
||||
if (JSFunction::Cast(result.GetTaggedObject())->GetMethod() ==
|
||||
JSFunction::Cast(func.GetTaggedObject())->GetMethod()) {
|
||||
return array->Get(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return JSTaggedValue::Hole();
|
||||
}
|
||||
|
||||
JSTaggedValue InvokeCache::Construct(JSThread *thread, JSTaggedValue firstValue, JSTaggedValue secondValue,
|
||||
JSTaggedValue ctor, JSTaggedValue newTarget, uint16_t firstArgIdx, uint16_t length)
|
||||
{
|
||||
// ic miss
|
||||
if (UNLIKELY(!firstValue.IsHeapObject())) {
|
||||
return JSTaggedValue::Hole();
|
||||
}
|
||||
|
||||
// gc protection
|
||||
JSHandle<JSFunction> constructor(thread, ctor);
|
||||
JSHandle<JSFunction> newTgt(thread, newTarget);
|
||||
|
||||
JSHandle<JSHClass> instanceHClass;
|
||||
// monomorphic
|
||||
if (LIKELY(firstValue.IsJSFunction() &&
|
||||
newTgt->GetMethod() == JSFunction::Cast(firstValue.GetTaggedObject())->GetMethod())) {
|
||||
instanceHClass = JSHandle<JSHClass>(thread, JSHClass::Cast(secondValue.GetTaggedObject()));
|
||||
} else {
|
||||
// polymorphic
|
||||
ASSERT(firstValue.IsTaggedArray());
|
||||
JSTaggedValue polyCache = CheckPolyInvokeCache(firstValue, newTarget);
|
||||
if (UNLIKELY(polyCache.IsHole())) {
|
||||
return JSTaggedValue::Hole();
|
||||
}
|
||||
instanceHClass = JSHandle<JSHClass>(thread, JSHClass::Cast(polyCache.GetTaggedObject()));
|
||||
}
|
||||
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSObject> obj = factory->NewJSObject(instanceHClass);
|
||||
|
||||
CVector<JSTaggedType> values;
|
||||
values.reserve(length);
|
||||
|
||||
InterpretedFrameHandler frameHandler(thread);
|
||||
CallParams params;
|
||||
params.callTarget = ECMAObject::Cast(*constructor);
|
||||
params.newTarget = newTgt.GetTaggedType();
|
||||
params.thisArg = obj.GetTaggedType();
|
||||
params.argc = length;
|
||||
for (array_size_t i = 0; i < length; ++i) {
|
||||
JSTaggedValue value = frameHandler.GetVRegValue(firstArgIdx + i);
|
||||
values.emplace_back(value.GetRawData());
|
||||
}
|
||||
params.argv = values.data();
|
||||
|
||||
EcmaInterpreter::Execute(thread, params);
|
||||
|
||||
return obj.GetTaggedValue();
|
||||
}
|
||||
|
||||
// just identify simple callee case which can be inlined, the implement of inline need wait TS AOT
|
||||
bool InvokeCache::SetMonoInlineCallCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
JSTaggedValue callee)
|
||||
{
|
||||
ASSERT(callee.IsJSFunction());
|
||||
JSMethod *calleeMethod = JSFunction::Cast(callee.GetTaggedObject())->GetMethod();
|
||||
if (DecideCanBeInlined(calleeMethod)) {
|
||||
profileTypeInfo->Set(thread, slotId, callee);
|
||||
return true;
|
||||
}
|
||||
|
||||
profileTypeInfo->Set(thread, slotId, JSTaggedValue::Hole());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InvokeCache::SetPolyInlineCallCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
uint8_t length, JSTaggedValue calleeArray)
|
||||
{
|
||||
ASSERT(calleeArray.IsTaggedArray() && length >= 2 && length <= 4);
|
||||
JSHandle<TaggedArray> calleeArr(thread, calleeArray);
|
||||
ASSERT(calleeArr->GetLength() == length);
|
||||
JSHandle<TaggedArray> profileTypeInfoArr(thread, profileTypeInfo);
|
||||
|
||||
auto factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> newArray = factory->NewTaggedArray(length);
|
||||
|
||||
for (uint8_t index = 0; index < length; ++index) {
|
||||
JSTaggedValue calleeElement = calleeArr->Get(index);
|
||||
JSMethod *calleeMethod = JSFunction::Cast(calleeElement.GetTaggedObject())->GetMethod();
|
||||
if (DecideCanBeInlined(calleeMethod)) {
|
||||
newArray->Set(thread, index, calleeElement);
|
||||
} else {
|
||||
newArray->Set(thread, index, JSTaggedValue::Hole());
|
||||
}
|
||||
}
|
||||
|
||||
profileTypeInfoArr->Set(thread, slotId, newArray);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvokeCache::DecideCanBeInlined(JSMethod *method)
|
||||
{
|
||||
constexpr uint32_t MAX_INLINED_BYTECODE_SIZE = 128;
|
||||
uint32_t bcSize = method->GetBytecodeArraySize();
|
||||
return (bcSize > 0 && bcSize < MAX_INLINED_BYTECODE_SIZE); // 0 is invalid
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_IC_INVOKE_CACHE_H_
|
||||
#define ECMASCRIPT_IC_INVOKE_CACHE_H_
|
||||
|
||||
#include "ecmascript/ic/profile_type_info.h"
|
||||
#include "ecmascript/js_tagged_value.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
class InvokeCache {
|
||||
public:
|
||||
static bool SetMonoConstuctCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
JSTaggedValue newTarget, JSTaggedValue initialHClass);
|
||||
|
||||
static bool SetPolyConstuctCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
uint8_t length, JSTaggedValue newTargetArray,
|
||||
JSTaggedValue initialHClassArray);
|
||||
|
||||
static JSTaggedValue CheckPolyInvokeCache(JSTaggedValue cachedArray, JSTaggedValue func);
|
||||
|
||||
static JSTaggedValue Construct(JSThread *thread, JSTaggedValue firstValue, JSTaggedValue secondValue,
|
||||
JSTaggedValue ctor, JSTaggedValue newTarget, uint16_t firstArgIdx,
|
||||
uint16_t length);
|
||||
|
||||
static bool SetMonoInlineCallCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
JSTaggedValue callee);
|
||||
|
||||
static bool SetPolyInlineCallCacheSlot(JSThread *thread, ProfileTypeInfo *profileTypeInfo, uint32_t slotId,
|
||||
uint8_t length, JSTaggedValue calleeArray);
|
||||
|
||||
static bool DecideCanBeInlined(JSMethod *method);
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // ECMASCRIPT_IC_INVOKE_CACHE_H_
|
||||
@@ -48,7 +48,6 @@ void ProfileTypeAccessor::AddHandlerWithoutKey(JSHandle<JSTaggedValue> dynclass,
|
||||
auto profileData = profileTypeInfo_->Get(slotId_);
|
||||
ASSERT(!profileData.IsHole());
|
||||
if (profileData.IsUndefined()) {
|
||||
ASSERT(profileTypeInfo_->Get(index + 1) == JSTaggedValue::Undefined());
|
||||
profileTypeInfo_->Set(thread_, index, GetWeakRef(dynclass.GetTaggedValue()));
|
||||
profileTypeInfo_->Set(thread_, index + 1, handler.GetTaggedValue());
|
||||
return;
|
||||
|
||||
@@ -57,7 +57,7 @@ private:
|
||||
|
||||
std::array<PropertyKey, CACHE_LENGTH> keys_{};
|
||||
|
||||
friend class EcmaVM;
|
||||
friend class JSThread;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_IC_PROPERTIES_CACHE_H
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# 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.
|
||||
|
||||
import("//ark/js_runtime/js_runtime_config.gni")
|
||||
import("//ark/js_runtime/test/test_helper.gni")
|
||||
import("//build/test.gni")
|
||||
|
||||
module_output_path = "ark/js_runtime"
|
||||
|
||||
host_unittest_action("ICBinaryOpTest") {
|
||||
module_out_path = module_output_path
|
||||
|
||||
sources = [
|
||||
# test file
|
||||
"ic_binaryop_test.cpp",
|
||||
]
|
||||
|
||||
configs = [
|
||||
"//ark/js_runtime:ecma_test_config",
|
||||
"//ark/js_runtime:ark_jsruntime_public_config", # should add before
|
||||
# arkruntime_public_config
|
||||
"//ark/js_runtime:ark_jsruntime_common_config",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"//ark/js_runtime:libark_jsruntime_test",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
|
||||
if (!is_standard_system) {
|
||||
deps += [ "$ark_root/runtime:libarkruntime" ]
|
||||
}
|
||||
}
|
||||
|
||||
host_unittest_action("ICCompareOpTest") {
|
||||
module_out_path = module_output_path
|
||||
|
||||
sources = [
|
||||
# test file
|
||||
"ic_compareop_test.cpp",
|
||||
]
|
||||
|
||||
configs = [
|
||||
"//ark/js_runtime:ecma_test_config",
|
||||
"//ark/js_runtime:ark_jsruntime_public_config", # should add before
|
||||
# arkruntime_public_config
|
||||
"//ark/js_runtime:ark_jsruntime_common_config",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"//ark/js_runtime:libark_jsruntime_test",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
|
||||
if (!is_standard_system) {
|
||||
deps += [ "$ark_root/runtime:libarkruntime" ]
|
||||
}
|
||||
}
|
||||
|
||||
host_unittest_action("ICInvokeTest") {
|
||||
module_out_path = module_output_path
|
||||
|
||||
sources = [
|
||||
# test file
|
||||
"ic_invoke_test.cpp",
|
||||
]
|
||||
|
||||
configs = [
|
||||
"//ark/js_runtime:ecma_test_config",
|
||||
"//ark/js_runtime:ark_jsruntime_public_config", # should add before
|
||||
# arkruntime_public_config
|
||||
"//ark/js_runtime:ark_jsruntime_common_config",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"//ark/js_runtime:libark_jsruntime_test",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
|
||||
if (!is_standard_system) {
|
||||
deps += [ "$ark_root/runtime:libarkruntime" ]
|
||||
}
|
||||
}
|
||||
|
||||
group("unittest") {
|
||||
testonly = true
|
||||
|
||||
# deps file
|
||||
deps = [
|
||||
":ICBinaryOpTest",
|
||||
":ICCompareOpTest",
|
||||
":ICInvokeTest",
|
||||
]
|
||||
}
|
||||
|
||||
group("host_unittest") {
|
||||
testonly = true
|
||||
|
||||
# deps file
|
||||
deps = [
|
||||
":ICBinaryOpTestAction",
|
||||
":ICCompareOpTestAction",
|
||||
":ICInvokeTestAction",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* 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 <thread>
|
||||
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/global_env_constants.h"
|
||||
#include "ecmascript/global_env_constants-inl.h"
|
||||
#include "ecmascript/ic/ic_binary_op-inl.h"
|
||||
#include "ecmascript/interpreter/interpreter-inl.h"
|
||||
#include "ecmascript/interpreter/slow_runtime_stub.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/tests/test_helper.h"
|
||||
|
||||
using namespace panda::ecmascript;
|
||||
namespace panda::test {
|
||||
class ICBinaryOPTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
GTEST_LOG_(INFO) << "SetUpTestCase";
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
GTEST_LOG_(INFO) << "TearDownCase";
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
|
||||
ecmaVm = EcmaVM::Cast(instance);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TestHelper::DestroyEcmaVMWithScope(instance, scope);
|
||||
}
|
||||
|
||||
PandaVM *instance {nullptr};
|
||||
EcmaHandleScope *scope {nullptr};
|
||||
JSThread *thread {nullptr};
|
||||
EcmaVM *ecmaVm = nullptr;
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, AddWithTSType)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
|
||||
JSHandle<EcmaString> Str1 = factory->NewFromCanBeCompressString("AddTest");
|
||||
JSHandle<EcmaString> Str2 = factory->NewFromCanBeCompressString("IC");
|
||||
JSHandle<JSObject> arg4 = factory->NewEmptyJSObject();
|
||||
JSTaggedValue arg1Value(static_cast<uint32_t>(2));
|
||||
JSTaggedValue arg2Value(static_cast<uint32_t>(3));
|
||||
JSTaggedValue arg3Value(static_cast<double>(9.5561));
|
||||
JSHandle<JSTaggedValue> arg1(thread, arg1Value);
|
||||
JSHandle<JSTaggedValue> arg2(thread, arg2Value);
|
||||
JSHandle<JSTaggedValue> arg3(thread, arg3Value);
|
||||
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, arg1.GetTaggedValue(),
|
||||
arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle1(thread, resInSlowPath1);
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::AddWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle1.GetTaggedValue(), resInICPath1);
|
||||
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, arg1.GetTaggedValue(),
|
||||
arg3.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle2(thread, resInSlowPath2);
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::AddWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), arg3.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle2.GetTaggedValue(), resInICPath2);
|
||||
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, Str1.GetTaggedValue(),
|
||||
Str2.GetTaggedValue());
|
||||
JSHandle<EcmaString> slowHandle3(thread, reinterpret_cast<EcmaString *>(resInSlowPath3.GetRawData()));
|
||||
JSTaggedValue resInICPath3 = ICBinaryOP::AddWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), Str2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::STRING)));
|
||||
ASSERT_TRUE(resInICPath3.IsString());
|
||||
EXPECT_EQ(slowHandle3->Compare(reinterpret_cast<EcmaString *>(resInICPath3.GetRawData())), 0);
|
||||
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, JSTaggedValue::Undefined(),
|
||||
arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle4(thread, resInSlowPath4);
|
||||
JSTaggedValue resInICPath4 = ICBinaryOP::AddWithTSType(thread, ecmaVm, JSTaggedValue::Undefined(),
|
||||
arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER_GEN)));
|
||||
EXPECT_EQ(slowHandle4.GetTaggedValue(), resInICPath4);
|
||||
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, arg3.GetTaggedValue(),
|
||||
Str1.GetTaggedValue());
|
||||
JSHandle<EcmaString> slowHandle5(thread, reinterpret_cast<EcmaString *>(resInSlowPath5.GetRawData()));
|
||||
JSTaggedValue resInICPath5 = ICBinaryOP::AddWithTSType(thread, ecmaVm, arg3.GetTaggedValue(),
|
||||
Str1.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::STRING_GEN)));
|
||||
ASSERT_TRUE(resInICPath5.IsString());
|
||||
EXPECT_EQ(slowHandle5->Compare(reinterpret_cast<EcmaString *>(resInICPath5.GetRawData())), 0);
|
||||
|
||||
JSTaggedValue resInSlowPath6 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, Str1.GetTaggedValue(),
|
||||
JSTaggedValue::Null());
|
||||
JSHandle<EcmaString> slowHandle6(thread, reinterpret_cast<EcmaString *>(resInSlowPath6.GetRawData()));
|
||||
JSTaggedValue resInICPath6 = ICBinaryOP::AddWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), JSTaggedValue::Null(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::STRING_GEN)));
|
||||
ASSERT_TRUE(resInICPath6.IsString());
|
||||
EXPECT_EQ(slowHandle6->Compare(reinterpret_cast<EcmaString *>(resInICPath6.GetRawData())), 0);
|
||||
|
||||
JSTaggedValue resInSlowPath7 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, arg1.GetTaggedValue(),
|
||||
JSTaggedValue::True());
|
||||
JSHandle<JSTaggedValue> slowHandle7(thread, resInSlowPath7);
|
||||
JSTaggedValue resInICPath7 = ICBinaryOP::AddWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), JSTaggedValue::True(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER_GEN)));
|
||||
EXPECT_EQ(slowHandle7.GetTaggedValue(), resInICPath7);
|
||||
|
||||
JSTaggedValue resInSlowPath8 = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, arg4.GetTaggedValue(),
|
||||
JSTaggedValue::Null());
|
||||
JSHandle<EcmaString> slowHandle8(thread, reinterpret_cast<EcmaString *>(resInSlowPath8.GetRawData()));
|
||||
JSTaggedValue resInICPath8 = ICBinaryOP::AddWithTSType(thread, ecmaVm, arg4.GetTaggedValue(), JSTaggedValue::Null(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
ASSERT_TRUE(resInICPath8.IsString());
|
||||
EXPECT_EQ(slowHandle8->Compare(reinterpret_cast<EcmaString *>(resInICPath8.GetRawData())), 0);
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, SubWithTSType)
|
||||
{
|
||||
JSTaggedValue arg1Value(static_cast<uint32_t>(-2));
|
||||
JSTaggedValue arg2Value(static_cast<uint32_t>(INT32_MAX-1));
|
||||
JSTaggedValue arg3Value(static_cast<double>(9.5561));
|
||||
JSHandle<JSTaggedValue> arg1(thread, arg1Value);
|
||||
JSHandle<JSTaggedValue> arg2(thread, arg2Value);
|
||||
JSHandle<JSTaggedValue> arg3(thread, arg3Value);
|
||||
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::Sub2Dyn(thread, arg1.GetTaggedValue(), arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle1(thread, resInSlowPath1);
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::SubWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle1.GetTaggedValue(), resInICPath1);
|
||||
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::Sub2Dyn(thread, arg2.GetTaggedValue(), arg3.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle2(thread, resInSlowPath2);
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::SubWithTSType(thread, ecmaVm, arg2.GetTaggedValue(), arg3.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle2.GetTaggedValue(), resInICPath2);
|
||||
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::Sub2Dyn(thread, arg1.GetTaggedValue(), JSTaggedValue::True());
|
||||
JSHandle<JSTaggedValue> slowHandle3(thread, resInSlowPath3);
|
||||
JSTaggedValue resInICPath3 = ICBinaryOP::SubWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), JSTaggedValue::True(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(slowHandle3.GetTaggedValue(), resInICPath3);
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, MulWithTSType)
|
||||
{
|
||||
JSTaggedValue arg1Value(static_cast<double>(28.5));
|
||||
JSTaggedValue arg2Value(static_cast<uint16_t>(354));
|
||||
JSTaggedValue arg3Value(static_cast<double>(9.5561));
|
||||
JSHandle<JSTaggedValue> arg1(thread, arg1Value);
|
||||
JSHandle<JSTaggedValue> arg2(thread, arg2Value);
|
||||
JSHandle<JSTaggedValue> arg3(thread, arg3Value);
|
||||
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::Mul2Dyn(thread, arg1.GetTaggedValue(), arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle1(thread, resInSlowPath1);
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::MulWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle1.GetTaggedValue(), resInICPath1);
|
||||
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::Mul2Dyn(thread, arg2.GetTaggedValue(), arg3.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle2(thread, resInSlowPath2);
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::MulWithTSType(thread, ecmaVm, arg2.GetTaggedValue(), arg3.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle2.GetTaggedValue(), resInICPath2);
|
||||
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::Mul2Dyn(thread, arg1.GetTaggedValue(), JSTaggedValue::True());
|
||||
JSHandle<JSTaggedValue> slowHandle3(thread, resInSlowPath3);
|
||||
JSTaggedValue resInICPath3 = ICBinaryOP::MulWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), JSTaggedValue::True(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(slowHandle3.GetTaggedValue(), resInICPath3);
|
||||
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, DivWithTSType)
|
||||
{
|
||||
JSTaggedValue arg1Value(static_cast<uint32_t>(2));
|
||||
JSTaggedValue arg2Value(static_cast<uint32_t>(39884));
|
||||
JSTaggedValue arg3Value(static_cast<uint32_t>(0));
|
||||
JSTaggedValue arg4Value(static_cast<double>(934.5561));
|
||||
JSHandle<JSTaggedValue> arg1(thread, arg1Value);
|
||||
JSHandle<JSTaggedValue> arg2(thread, arg2Value);
|
||||
JSHandle<JSTaggedValue> arg3(thread, arg3Value);
|
||||
JSHandle<JSTaggedValue> arg4(thread, arg4Value);
|
||||
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::Div2Dyn(thread, arg3.GetTaggedValue(), arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle1(thread, resInSlowPath1);
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::DivWithTSType(thread, ecmaVm, arg3.GetTaggedValue(), arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle1.GetTaggedValue(), resInICPath1);
|
||||
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::Div2Dyn(thread, arg2.GetTaggedValue(), arg3.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle2(thread, resInSlowPath2);
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::DivWithTSType(thread, ecmaVm, arg2.GetTaggedValue(), arg3.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle2.GetTaggedValue(), resInICPath2);
|
||||
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::Div2Dyn(thread, arg1.GetTaggedValue(), arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle3(thread, resInSlowPath3);
|
||||
JSTaggedValue resInICPath3 = ICBinaryOP::DivWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle3.GetTaggedValue(), resInICPath3);
|
||||
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::Div2Dyn(thread, arg2.GetTaggedValue(), JSTaggedValue::True());
|
||||
JSHandle<JSTaggedValue> slowHandle4(thread, resInSlowPath4);
|
||||
JSTaggedValue resInICPath4 = ICBinaryOP::DivWithTSType(thread, ecmaVm, arg2.GetTaggedValue(), JSTaggedValue::True(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(slowHandle4.GetTaggedValue(), resInICPath4);
|
||||
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::Div2Dyn(thread, arg4.GetTaggedValue(), JSTaggedValue::False());
|
||||
JSHandle<JSTaggedValue> slowHandle5(thread, resInSlowPath5);
|
||||
JSTaggedValue resInICPath5 = ICBinaryOP::DivWithTSType(thread, ecmaVm, arg4.GetTaggedValue(),
|
||||
JSTaggedValue::False(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(slowHandle5.GetTaggedValue(), resInICPath5);
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, ModWithTSType)
|
||||
{
|
||||
JSTaggedValue arg1Value(static_cast<uint32_t>(2));
|
||||
JSTaggedValue arg2Value(static_cast<uint32_t>(39884));
|
||||
JSTaggedValue arg3Value(static_cast<uint32_t>(0));
|
||||
JSTaggedValue arg4Value(static_cast<double>(934.5561));
|
||||
JSHandle<JSTaggedValue> arg1(thread, arg1Value);
|
||||
JSHandle<JSTaggedValue> arg2(thread, arg2Value);
|
||||
JSHandle<JSTaggedValue> arg3(thread, arg3Value);
|
||||
JSHandle<JSTaggedValue> arg4(thread, arg4Value);
|
||||
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::Mod2Dyn(thread, arg3.GetTaggedValue(), arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle1(thread, resInSlowPath1);
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::ModWithTSType(thread, ecmaVm, arg3.GetTaggedValue(), arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle1.GetTaggedValue(), resInICPath1);
|
||||
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::Mod2Dyn(thread, arg2.GetTaggedValue(), arg3.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle2(thread, resInSlowPath2);
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::ModWithTSType(thread, ecmaVm, arg2.GetTaggedValue(), arg3.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle2.GetTaggedValue(), resInICPath2);
|
||||
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::Mod2Dyn(thread, arg1.GetTaggedValue(), arg2.GetTaggedValue());
|
||||
JSHandle<JSTaggedValue> slowHandle3(thread, resInSlowPath3);
|
||||
JSTaggedValue resInICPath3 = ICBinaryOP::ModWithTSType(thread, ecmaVm, arg1.GetTaggedValue(), arg2.GetTaggedValue(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(slowHandle3.GetTaggedValue(), resInICPath3);
|
||||
|
||||
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::Mod2Dyn(thread, arg2.GetTaggedValue(), JSTaggedValue::True());
|
||||
JSHandle<JSTaggedValue> slowHandle4(thread, resInSlowPath4);
|
||||
JSTaggedValue resInICPath4 = ICBinaryOP::ModWithTSType(thread, ecmaVm, arg2.GetTaggedValue(), JSTaggedValue::True(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(slowHandle4.GetTaggedValue(), resInICPath4);
|
||||
|
||||
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::Mod2Dyn(thread, arg4.GetTaggedValue(), JSTaggedValue::False());
|
||||
JSHandle<JSTaggedValue> slowHandle5(thread, resInSlowPath5);
|
||||
JSTaggedValue resInICPath5 = ICBinaryOP::ModWithTSType(thread, ecmaVm, arg4.GetTaggedValue(),
|
||||
JSTaggedValue::False(),
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(slowHandle5.GetTaggedValue(), resInICPath5);
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, ShlWithTSType)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<EcmaString> Str1 = factory->NewFromCanBeCompressString("225");
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(286));
|
||||
JSTaggedValue arg3(static_cast<uint32_t>(5));
|
||||
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::ShlWithTSType(thread, ecmaVm, arg1, arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(JSTaggedValue(9152), resInICPath1);
|
||||
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::ShlWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(JSTaggedValue(7200), resInICPath2);
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, ShrWithTSType)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<EcmaString> Str1 = factory->NewFromCanBeCompressString("225");
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(286));
|
||||
JSTaggedValue arg3(static_cast<uint32_t>(5));
|
||||
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::ShrWithTSType(thread, ecmaVm, arg1, arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(JSTaggedValue(8), resInICPath1);
|
||||
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::ShrWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(JSTaggedValue(7), resInICPath2);
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICBinaryOPTest, AshrWithTSType)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<EcmaString> Str1 = factory->NewFromCanBeCompressString("225");
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(286));
|
||||
JSTaggedValue arg2(static_cast<uint32_t>(-286));
|
||||
JSTaggedValue arg3(static_cast<uint32_t>(5));
|
||||
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::AshrWithTSType(thread, ecmaVm, arg1, arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(JSTaggedValue(8), resInICPath1);
|
||||
|
||||
JSTaggedValue resInICPath3 = ICBinaryOP::AshrWithTSType(thread, ecmaVm, arg2, arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(JSTaggedValue(134217719), resInICPath3);
|
||||
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::AshrWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(JSTaggedValue(7), resInICPath2);
|
||||
|
||||
};
|
||||
HWTEST_F_L0(ICBinaryOPTest, AndWithTSType)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<EcmaString> Str1 = factory->NewFromCanBeCompressString("225");
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(286));
|
||||
JSTaggedValue arg3(static_cast<uint32_t>(541));
|
||||
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::AndWithTSType(thread, ecmaVm, arg1, arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(JSTaggedValue(28), resInICPath1);
|
||||
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::AndWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(JSTaggedValue(1), resInICPath2);
|
||||
};
|
||||
HWTEST_F_L0(ICBinaryOPTest, OrWithTSType)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<EcmaString> Str1 = factory->NewFromCanBeCompressString("225");
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(286));
|
||||
JSTaggedValue arg3(static_cast<uint32_t>(523));
|
||||
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::OrWithTSType(thread, ecmaVm, arg1, arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(JSTaggedValue(799), resInICPath1);
|
||||
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::OrWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(JSTaggedValue(747), resInICPath2);
|
||||
};
|
||||
HWTEST_F_L0(ICBinaryOPTest, XorWithTSType)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<EcmaString> Str1 = factory->NewFromCanBeCompressString("1225");
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(286));
|
||||
JSTaggedValue arg3(static_cast<uint32_t>(523));
|
||||
|
||||
JSTaggedValue resInICPath1 = ICBinaryOP::XorWithTSType(thread, ecmaVm, arg1, arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::NUMBER)));
|
||||
EXPECT_EQ(JSTaggedValue(789), resInICPath1);
|
||||
|
||||
JSTaggedValue resInICPath2 = ICBinaryOP::XorWithTSType(thread, ecmaVm, Str1.GetTaggedValue(), arg3,
|
||||
JSTaggedValue(static_cast<int>(BinaryType::GENERIC)));
|
||||
EXPECT_EQ(JSTaggedValue(1730), resInICPath2);
|
||||
};
|
||||
} // namespace panda::test
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* 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 <thread>
|
||||
#include "ecmascript/builtins/builtins_boolean.h"
|
||||
#include "ecmascript/ecma_runtime_call_info.h"
|
||||
#include "ecmascript/ecma_string.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/global_env_constants.h"
|
||||
#include "ecmascript/global_env_constants-inl.h"
|
||||
#include "ecmascript/ic/ic_compare_op.cpp"
|
||||
#include "ecmascript/ic/ic_compare_op.h"
|
||||
#include "ecmascript/interpreter/slow_runtime_stub.h"
|
||||
#include "ecmascript/js_primitive_ref.h"
|
||||
#include "ecmascript/js_tagged_value-inl.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/tests/test_helper.h"
|
||||
|
||||
using namespace panda::ecmascript;
|
||||
namespace panda::test {
|
||||
class IcCompareOPTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
GTEST_LOG_(INFO) << "SetUpTestCase";
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
GTEST_LOG_(INFO) << "TearDownCase";
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
|
||||
ecmaVm = EcmaVM::Cast(instance);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TestHelper::DestroyEcmaVMWithScope(instance, scope);
|
||||
}
|
||||
|
||||
PandaVM *instance {nullptr};
|
||||
EcmaVM *ecmaVm = nullptr;
|
||||
EcmaHandleScope *scope {nullptr};
|
||||
JSThread *thread {nullptr};
|
||||
};
|
||||
|
||||
HWTEST_F_L0(IcCompareOPTest, EqualWithIC)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<JSTaggedValue> Str1 = JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("1"));
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(1));
|
||||
JSTaggedValue arg2(static_cast<double>(1.0));
|
||||
JSTaggedValue arg3(false);
|
||||
JSTaggedValue arg4(true);
|
||||
JSHandle<JSTaggedValue> arg1Handle(thread, arg1);
|
||||
JSHandle<JSTaggedValue> arg2Handle(thread, arg2);
|
||||
JSHandle<JSTaggedValue> arg3Handle(thread, arg3);
|
||||
JSHandle<JSTaggedValue> arg4Handle(thread, arg4);
|
||||
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
|
||||
|
||||
JSHandle<JSFunction> boolean(env->GetBooleanFunction());
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*boolean), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(boolean.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(1)));
|
||||
|
||||
JSTaggedValue booleanObj = builtins::BuiltinsBoolean::BooleanConstructor(ecmaRuntimeCallInfo.get());
|
||||
JSHandle<JSTaggedValue> booleanObjHandle(thread, booleanObj);
|
||||
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::EqDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::EqDyn(thread, Str1.GetTaggedValue(), arg1Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::EqDyn(thread, Str1.GetTaggedValue(), arg3Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::EqDyn(thread, Str1.GetTaggedValue(), arg4Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::EqDyn(thread, booleanObjHandle.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath9 = SlowRuntimeStub::EqDyn(thread, JSTaggedValue::Undefined(), JSTaggedValue::Null());
|
||||
JSTaggedValue resInSlowPath10 = SlowRuntimeStub::EqDyn(thread, JSTaggedValue::Undefined(), JSTaggedValue::True());
|
||||
|
||||
JSTaggedValue resInICPath1 = CompareOp::EqualWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue(), CompareOpType::NUMBER_NUMBER);
|
||||
JSTaggedValue resInICPath2 = CompareOp::EqualWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue(), CompareOpType::STRING_NUMBER);
|
||||
JSTaggedValue resInICPath3 = CompareOp::EqualWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath4 = CompareOp::EqualWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath5 = CompareOp::EqualWithIC(thread, booleanObjHandle.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue(), CompareOpType::OBJ_BOOLEAN);
|
||||
JSTaggedValue resInICPath9 = CompareOp::EqualWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null(), CompareOpType::UNDEFINED_NULL);
|
||||
JSTaggedValue resInICPath10 = CompareOp::EqualWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True(), CompareOpType::OTHER);
|
||||
|
||||
EXPECT_EQ(resInSlowPath1, resInICPath1);
|
||||
EXPECT_EQ(resInSlowPath2, resInICPath2);
|
||||
EXPECT_EQ(resInSlowPath3, resInICPath3);
|
||||
EXPECT_EQ(resInSlowPath4, resInICPath4);
|
||||
EXPECT_EQ(resInSlowPath5, resInICPath5);
|
||||
EXPECT_EQ(resInSlowPath9, resInICPath9);
|
||||
EXPECT_EQ(resInSlowPath10, resInICPath10);
|
||||
};
|
||||
|
||||
HWTEST_F_L0(IcCompareOPTest, NotEqualWithIC)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<JSTaggedValue> Str1 = JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("1"));
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(1));
|
||||
JSTaggedValue arg2(static_cast<double>(2.0));
|
||||
JSTaggedValue arg3(false);
|
||||
JSTaggedValue arg4(true);
|
||||
JSHandle<JSTaggedValue> arg1Handle(thread, arg1);
|
||||
JSHandle<JSTaggedValue> arg2Handle(thread, arg2);
|
||||
JSHandle<JSTaggedValue> arg3Handle(thread, arg3);
|
||||
JSHandle<JSTaggedValue> arg4Handle(thread, arg4);
|
||||
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
|
||||
|
||||
JSHandle<JSFunction> boolean(env->GetBooleanFunction());
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*boolean), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(boolean.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(123)));
|
||||
|
||||
JSTaggedValue booleanObj = builtins::BuiltinsBoolean::BooleanConstructor(ecmaRuntimeCallInfo.get());
|
||||
JSHandle<JSTaggedValue> booleanObjHandle(thread, booleanObj);
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::NotEqDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::NotEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::NotEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::NotEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::NotEqDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath9 = SlowRuntimeStub::NotEqDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null());
|
||||
JSTaggedValue resInSlowPath10 = SlowRuntimeStub::NotEqDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True());
|
||||
|
||||
JSTaggedValue resInICPath1 = CompareOp::NotEqualWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_NUMBER);
|
||||
JSTaggedValue resInICPath2 = CompareOp::NotEqualWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue(), CompareOpType::STRING_NUMBER);
|
||||
JSTaggedValue resInICPath3 = CompareOp::NotEqualWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath4 = CompareOp::NotEqualWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath5 = CompareOp::NotEqualWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_OBJ);
|
||||
JSTaggedValue resInICPath9 = CompareOp::NotEqualWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null(), CompareOpType::UNDEFINED_NULL);
|
||||
JSTaggedValue resInICPath10 = CompareOp::NotEqualWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True(), CompareOpType::OTHER);
|
||||
|
||||
EXPECT_EQ(resInSlowPath1, resInICPath1);
|
||||
EXPECT_EQ(resInSlowPath2, resInICPath2);
|
||||
EXPECT_EQ(resInSlowPath3, resInICPath3);
|
||||
EXPECT_EQ(resInSlowPath4, resInICPath4);
|
||||
EXPECT_EQ(resInSlowPath5, resInICPath5);
|
||||
EXPECT_EQ(resInSlowPath9, resInICPath9);
|
||||
EXPECT_EQ(resInSlowPath10, resInICPath10);
|
||||
};
|
||||
|
||||
|
||||
HWTEST_F_L0(IcCompareOPTest, LessDynWithIC)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<JSTaggedValue> Str1 = JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("0"));
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(1));
|
||||
JSTaggedValue arg2(static_cast<double>(0.5));
|
||||
JSTaggedValue arg3(false);
|
||||
JSTaggedValue arg4(true);
|
||||
JSHandle<JSTaggedValue> arg1Handle(thread, arg1);
|
||||
JSHandle<JSTaggedValue> arg2Handle(thread, arg2);
|
||||
JSHandle<JSTaggedValue> arg3Handle(thread, arg3);
|
||||
JSHandle<JSTaggedValue> arg4Handle(thread, arg4);
|
||||
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
|
||||
|
||||
JSHandle<JSFunction> boolean(env->GetBooleanFunction());
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*boolean), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(boolean.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(123)));
|
||||
|
||||
JSTaggedValue booleanObj = builtins::BuiltinsBoolean::BooleanConstructor(ecmaRuntimeCallInfo.get());
|
||||
JSHandle<JSTaggedValue> booleanObjHandle(thread, booleanObj);
|
||||
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::LessDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::LessDyn(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::LessDyn(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::LessDyn(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::LessDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath9 = SlowRuntimeStub::LessDyn(thread,
|
||||
JSTaggedValue::Undefined(), JSTaggedValue::Null());
|
||||
JSTaggedValue resInSlowPath10 = SlowRuntimeStub::LessDyn(thread,
|
||||
JSTaggedValue::Undefined(), JSTaggedValue::True());
|
||||
|
||||
JSTaggedValue resInICPath1 = CompareOp::LessDynWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue(), CompareOpType::NUMBER_NUMBER);
|
||||
JSTaggedValue resInICPath2 = CompareOp::LessDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue(), CompareOpType::STRING_NUMBER);
|
||||
JSTaggedValue resInICPath3 = CompareOp::LessDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath4 = CompareOp::LessDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue(), CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath5 = CompareOp::LessDynWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_OBJ);
|
||||
JSTaggedValue resInICPath9 = CompareOp::LessDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null(), CompareOpType::UNDEFINED_NULL);
|
||||
JSTaggedValue resInICPath10 = CompareOp::LessDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True(), CompareOpType::OTHER);
|
||||
|
||||
EXPECT_EQ(resInSlowPath1, resInICPath1);
|
||||
EXPECT_EQ(resInSlowPath2, resInICPath2);
|
||||
EXPECT_EQ(resInSlowPath3, resInICPath3);
|
||||
EXPECT_EQ(resInSlowPath4, resInICPath4);
|
||||
EXPECT_EQ(resInSlowPath5, resInICPath5);
|
||||
EXPECT_EQ(resInSlowPath9, resInICPath9);
|
||||
EXPECT_EQ(resInSlowPath10, resInICPath10);
|
||||
};
|
||||
|
||||
|
||||
HWTEST_F_L0(IcCompareOPTest, LessEqDynWithIC)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<JSTaggedValue> Str1 = JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("1"));
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(1));
|
||||
JSTaggedValue arg2(static_cast<double>(0.5));
|
||||
JSTaggedValue arg3(false);
|
||||
JSTaggedValue arg4(true);
|
||||
JSHandle<JSTaggedValue> arg1Handle(thread, arg1);
|
||||
JSHandle<JSTaggedValue> arg2Handle(thread, arg2);
|
||||
JSHandle<JSTaggedValue> arg3Handle(thread, arg3);
|
||||
JSHandle<JSTaggedValue> arg4Handle(thread, arg4);
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
|
||||
|
||||
JSHandle<JSFunction> boolean(env->GetBooleanFunction());
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*boolean), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(boolean.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(123)));
|
||||
|
||||
JSTaggedValue booleanObj = builtins::BuiltinsBoolean::BooleanConstructor(ecmaRuntimeCallInfo.get());
|
||||
JSHandle<JSTaggedValue> booleanObjHandle(thread, booleanObj);
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::LessEqDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::LessEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::LessEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::LessEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::LessEqDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath9 = SlowRuntimeStub::LessEqDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null());
|
||||
JSTaggedValue resInSlowPath10 = SlowRuntimeStub::LessEqDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True());
|
||||
JSTaggedValue resInICPath1 = CompareOp::LessEqDynWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_NUMBER);
|
||||
JSTaggedValue resInICPath2 = CompareOp::LessEqDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_NUMBER);
|
||||
JSTaggedValue resInICPath3 = CompareOp::LessEqDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath4 = CompareOp::LessEqDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath5 = CompareOp::LessEqDynWithIC(thread,
|
||||
arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_OBJ);
|
||||
JSTaggedValue resInICPath9 = CompareOp::LessEqDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null(), CompareOpType::UNDEFINED_NULL);
|
||||
JSTaggedValue resInICPath10 = CompareOp::LessEqDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True(), CompareOpType::OTHER);
|
||||
|
||||
EXPECT_EQ(resInSlowPath1, resInICPath1);
|
||||
EXPECT_EQ(resInSlowPath2, resInICPath2);
|
||||
EXPECT_EQ(resInSlowPath3, resInICPath3);
|
||||
EXPECT_EQ(resInSlowPath4, resInICPath4);
|
||||
EXPECT_EQ(resInSlowPath5, resInICPath5);
|
||||
EXPECT_EQ(resInSlowPath9, resInICPath9);
|
||||
EXPECT_EQ(resInSlowPath10, resInICPath10);
|
||||
};
|
||||
|
||||
|
||||
HWTEST_F_L0(IcCompareOPTest, GreaterDynWithIC)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<JSTaggedValue> Str1 = JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("1"));
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(1));
|
||||
JSTaggedValue arg2(static_cast<double>(1.0));
|
||||
JSTaggedValue arg3(false);
|
||||
JSTaggedValue arg4(true);
|
||||
JSHandle<JSTaggedValue> arg1Handle(thread, arg1);
|
||||
JSHandle<JSTaggedValue> arg2Handle(thread, arg2);
|
||||
JSHandle<JSTaggedValue> arg3Handle(thread, arg3);
|
||||
JSHandle<JSTaggedValue> arg4Handle(thread, arg4);
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
|
||||
|
||||
JSHandle<JSFunction> boolean(env->GetBooleanFunction());
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*boolean), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(boolean.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(1)));
|
||||
|
||||
JSTaggedValue booleanObj = builtins::BuiltinsBoolean::BooleanConstructor(ecmaRuntimeCallInfo.get());
|
||||
JSHandle<JSTaggedValue> booleanObjHandle(thread, booleanObj);
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::GreaterDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::GreaterDyn(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::GreaterDyn(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::GreaterDyn(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::GreaterDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath9 = SlowRuntimeStub::GreaterDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null());
|
||||
JSTaggedValue resInSlowPath10 = SlowRuntimeStub::GreaterDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True());
|
||||
|
||||
JSTaggedValue resInICPath1 = CompareOp::GreaterDynWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_NUMBER);
|
||||
JSTaggedValue resInICPath2 = CompareOp::GreaterDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_NUMBER);
|
||||
JSTaggedValue resInICPath3 = CompareOp::GreaterDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath4 = CompareOp::GreaterDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath5 = CompareOp::GreaterDynWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_OBJ);
|
||||
JSTaggedValue resInICPath9 = CompareOp::GreaterDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null(), CompareOpType::UNDEFINED_NULL);
|
||||
JSTaggedValue resInICPath10 = CompareOp::GreaterDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True(), CompareOpType::OTHER);
|
||||
|
||||
EXPECT_EQ(resInSlowPath1, resInICPath1);
|
||||
EXPECT_EQ(resInSlowPath2, resInICPath2);
|
||||
EXPECT_EQ(resInSlowPath3, resInICPath3);
|
||||
EXPECT_EQ(resInSlowPath4, resInICPath4);
|
||||
EXPECT_EQ(resInSlowPath5, resInICPath5);
|
||||
EXPECT_EQ(resInSlowPath9, resInICPath9);
|
||||
EXPECT_EQ(resInSlowPath10, resInICPath10);
|
||||
};
|
||||
|
||||
|
||||
HWTEST_F_L0(IcCompareOPTest, GreaterEqDynWithIC)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
|
||||
JSHandle<JSTaggedValue> Str1 = JSHandle<JSTaggedValue>(factory->NewFromCanBeCompressString("1"));
|
||||
JSTaggedValue arg1(static_cast<uint32_t>(1));
|
||||
JSTaggedValue arg2(static_cast<double>(1.0));
|
||||
JSTaggedValue arg3(false);
|
||||
JSTaggedValue arg4(true);
|
||||
JSHandle<JSTaggedValue> arg1Handle(thread, arg1);
|
||||
JSHandle<JSTaggedValue> arg2Handle(thread, arg2);
|
||||
JSHandle<JSTaggedValue> arg3Handle(thread, arg3);
|
||||
JSHandle<JSTaggedValue> arg4Handle(thread, arg4);
|
||||
|
||||
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
|
||||
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
|
||||
|
||||
JSHandle<JSFunction> boolean(env->GetBooleanFunction());
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*boolean), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(boolean.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(0)));
|
||||
|
||||
JSTaggedValue booleanObj = builtins::BuiltinsBoolean::BooleanConstructor(ecmaRuntimeCallInfo.get());
|
||||
JSHandle<JSTaggedValue> booleanObjHandle(thread, booleanObj);
|
||||
JSTaggedValue resInSlowPath1 = SlowRuntimeStub::GreaterEqDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath2 = SlowRuntimeStub::GreaterEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath3 = SlowRuntimeStub::GreaterEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath4 = SlowRuntimeStub::GreaterEqDyn(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath5 = SlowRuntimeStub::GreaterEqDyn(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue());
|
||||
JSTaggedValue resInSlowPath9 = SlowRuntimeStub::GreaterEqDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null());
|
||||
JSTaggedValue resInSlowPath10 = SlowRuntimeStub::GreaterEqDyn(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True());
|
||||
|
||||
JSTaggedValue resInICPath1 = CompareOp::GreaterEqDynWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
arg2Handle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_NUMBER);
|
||||
JSTaggedValue resInICPath2 = CompareOp::GreaterEqDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg1Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_NUMBER);
|
||||
JSTaggedValue resInICPath3 = CompareOp::GreaterEqDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg3Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath4 = CompareOp::GreaterEqDynWithIC(thread, Str1.GetTaggedValue(),
|
||||
arg4Handle.GetTaggedValue(),
|
||||
CompareOpType::STRING_BOOLEAN);
|
||||
JSTaggedValue resInICPath5 = CompareOp::GreaterEqDynWithIC(thread, arg1Handle.GetTaggedValue(),
|
||||
booleanObjHandle.GetTaggedValue(),
|
||||
CompareOpType::NUMBER_OBJ);
|
||||
JSTaggedValue resInICPath9 = CompareOp::GreaterEqDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::Null(), CompareOpType::UNDEFINED_NULL);
|
||||
JSTaggedValue resInICPath10 = CompareOp::GreaterEqDynWithIC(thread, JSTaggedValue::Undefined(),
|
||||
JSTaggedValue::True(), CompareOpType::OTHER);
|
||||
|
||||
EXPECT_EQ(resInSlowPath1, resInICPath1);
|
||||
EXPECT_EQ(resInSlowPath2, resInICPath2);
|
||||
EXPECT_EQ(resInSlowPath3, resInICPath3);
|
||||
EXPECT_EQ(resInSlowPath4, resInICPath4);
|
||||
EXPECT_EQ(resInSlowPath5, resInICPath5);
|
||||
EXPECT_EQ(resInSlowPath9, resInICPath9);
|
||||
EXPECT_EQ(resInSlowPath10, resInICPath10);
|
||||
};
|
||||
} // namespace panda::test
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 <thread>
|
||||
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/ic/invoke_cache.h"
|
||||
#include "ecmascript/interpreter/interpreter-inl.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/tests/test_helper.h"
|
||||
|
||||
using namespace panda::ecmascript;
|
||||
namespace panda::test {
|
||||
class ICInvokeTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
GTEST_LOG_(INFO) << "SetUpTestCase";
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
GTEST_LOG_(INFO) << "TearDownCase";
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
|
||||
ecmaVm = EcmaVM::Cast(instance);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TestHelper::DestroyEcmaVMWithScope(instance, scope);
|
||||
}
|
||||
|
||||
PandaVM *instance {nullptr};
|
||||
EcmaVM *ecmaVm = nullptr;
|
||||
EcmaHandleScope *scope {nullptr};
|
||||
JSThread *thread {nullptr};
|
||||
};
|
||||
|
||||
HWTEST_F_L0(ICInvokeTest, SetMonoConstuctCacheSlot)
|
||||
{
|
||||
auto globalEnv = ecmaVm->GetGlobalEnv();
|
||||
auto factory = ecmaVm->GetFactory();
|
||||
JSHandle<JSFunction> func = factory->NewJSFunction(globalEnv);
|
||||
func.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassConstructor(true);
|
||||
|
||||
JSHandle<TaggedArray> array = factory->NewTaggedArray(10);
|
||||
uint32_t slotId = 5;
|
||||
bool setResult = InvokeCache::SetMonoConstuctCacheSlot(
|
||||
thread, static_cast<ProfileTypeInfo *>(*array), slotId, func.GetTaggedValue(), JSTaggedValue(123));
|
||||
ASSERT_TRUE(setResult);
|
||||
ASSERT_EQ(array->Get(thread, slotId), func.GetTaggedValue());
|
||||
ASSERT_EQ(array->Get(thread, slotId + 1), JSTaggedValue(123));
|
||||
}
|
||||
|
||||
HWTEST_F_L0(ICInvokeTest, SetPolyConstuctCacheSlot)
|
||||
{
|
||||
auto globalEnv = ecmaVm->GetGlobalEnv();
|
||||
auto factory = ecmaVm->GetFactory();
|
||||
JSHandle<TaggedArray> array1 = factory->NewTaggedArray(3);
|
||||
JSHandle<TaggedArray> array2 = factory->NewTaggedArray(3);
|
||||
|
||||
JSHandle<JSFunction> func0 = factory->NewJSFunction(globalEnv);
|
||||
func0.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassConstructor(true);
|
||||
array1->Set(thread, 0, func0.GetTaggedValue());
|
||||
array2->Set(thread, 0, JSTaggedValue(123));
|
||||
JSHandle<JSFunction> func1 = factory->NewJSFunction(globalEnv);
|
||||
func1.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassConstructor(true);
|
||||
array1->Set(thread, 1, func1.GetTaggedValue());
|
||||
array2->Set(thread, 1, JSTaggedValue(456));
|
||||
JSHandle<JSFunction> func2 = factory->NewJSFunction(globalEnv);
|
||||
func2.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassConstructor(true);
|
||||
array1->Set(thread, 2, func2.GetTaggedValue());
|
||||
array2->Set(thread, 2, JSTaggedValue(789));
|
||||
|
||||
JSHandle<TaggedArray> array = factory->NewTaggedArray(10);
|
||||
uint32_t slotId = 5;
|
||||
bool setResult = InvokeCache::SetPolyConstuctCacheSlot(
|
||||
thread, static_cast<ProfileTypeInfo *>(*array), slotId, 3, array1.GetTaggedValue(), array2.GetTaggedValue());
|
||||
ASSERT_TRUE(setResult);
|
||||
JSTaggedValue slot = array->Get(thread, slotId);
|
||||
ASSERT_TRUE(slot.IsTaggedArray());
|
||||
JSHandle<TaggedArray> slotArray(thread, slot);
|
||||
ASSERT_EQ(slotArray->Get(thread, 0), func0.GetTaggedValue());
|
||||
ASSERT_EQ(slotArray->Get(thread, 1), JSTaggedValue(123));
|
||||
ASSERT_EQ(slotArray->Get(thread, 2), func1.GetTaggedValue());
|
||||
ASSERT_EQ(slotArray->Get(thread, 3), JSTaggedValue(456));
|
||||
ASSERT_EQ(slotArray->Get(thread, 4), func2.GetTaggedValue());
|
||||
ASSERT_EQ(slotArray->Get(thread, 5), JSTaggedValue(789));
|
||||
ASSERT_EQ(array->Get(thread, slotId + 1), JSTaggedValue::Hole());
|
||||
}
|
||||
|
||||
HWTEST_F_L0(ICInvokeTest, CheckPolyInvokeCache)
|
||||
{
|
||||
auto globalEnv = ecmaVm->GetGlobalEnv();
|
||||
auto factory = ecmaVm->GetFactory();
|
||||
JSHandle<TaggedArray> array = factory->NewTaggedArray(6);
|
||||
|
||||
JSHandle<JSFunction> func0 = factory->NewJSFunction(globalEnv);
|
||||
JSHandle<JSFunction> func1 = factory->NewJSFunction(globalEnv);
|
||||
JSHandle<JSFunction> func2 = factory->NewJSFunction(globalEnv);
|
||||
JSHandle<JSFunction> func3 = factory->NewJSFunction(globalEnv);
|
||||
array->Set(thread, 0, func0.GetTaggedValue());
|
||||
array->Set(thread, 1, JSTaggedValue(123));
|
||||
array->Set(thread, 2, func1.GetTaggedValue());
|
||||
array->Set(thread, 3, JSTaggedValue(456));
|
||||
array->Set(thread, 4, func2.GetTaggedValue());
|
||||
array->Set(thread, 5, JSTaggedValue(789));
|
||||
|
||||
JSTaggedValue testValue0 = InvokeCache::CheckPolyInvokeCache(array.GetTaggedValue(), func0.GetTaggedValue());
|
||||
ASSERT_EQ(testValue0, JSTaggedValue(123));
|
||||
JSTaggedValue testValue1 = InvokeCache::CheckPolyInvokeCache(array.GetTaggedValue(), func1.GetTaggedValue());
|
||||
ASSERT_EQ(testValue1, JSTaggedValue(456));
|
||||
JSTaggedValue testValue2 = InvokeCache::CheckPolyInvokeCache(array.GetTaggedValue(), func2.GetTaggedValue());
|
||||
ASSERT_EQ(testValue2, JSTaggedValue(789));
|
||||
JSTaggedValue testValue3 = InvokeCache::CheckPolyInvokeCache(array.GetTaggedValue(), func3.GetTaggedValue());
|
||||
ASSERT_EQ(testValue3, JSTaggedValue::Hole());
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,9 @@ void InternalCallParams::MakeArgv(const EcmaRuntimeCallInfo *info, uint32_t posi
|
||||
|
||||
void InternalCallParams::MakeArgListWithHole(const TaggedArray *argv, uint32_t length)
|
||||
{
|
||||
if (length > argv->GetLength()) {
|
||||
length = argv->GetLength();
|
||||
}
|
||||
ASSERT(length <= argv->GetLength());
|
||||
if (LIKELY(length <= InternalCallParams::RESERVE_INTERNAL_CALL_PARAMS_FIXED_LENGTH)) {
|
||||
EnableFixedModeAndSetLength(length);
|
||||
@@ -118,15 +121,11 @@ void InternalCallParams::Iterate(const RootRangeVisitor &v) const
|
||||
uintptr_t start = 0U;
|
||||
uintptr_t end = 0U;
|
||||
if (LIKELY(IsFixedMode())) {
|
||||
JSTaggedType first = GetFixedBuffer(0);
|
||||
start = ToUintPtr(&first);
|
||||
JSTaggedType last = GetFixedBuffer(fixed_length_ - 1);
|
||||
end = ToUintPtr(&last);
|
||||
start = GetFixedDataAddress();
|
||||
end = start + sizeof(TaggedType) * fixed_length_;
|
||||
} else {
|
||||
JSTaggedType first = GetVariableBuffer(0);
|
||||
start = ToUintPtr(&first);
|
||||
JSTaggedType last = GetVariableBuffer(variable_length_ - 1);
|
||||
end = ToUintPtr(&last);
|
||||
start = GetVariableDataAddress();
|
||||
end = start + sizeof(TaggedType) * variable_length_;
|
||||
}
|
||||
v(Root::ROOT_INTERNAL_CALL_PARAMS, ObjectSlot(start), ObjectSlot(end));
|
||||
}
|
||||
|
||||
@@ -155,6 +155,11 @@ private:
|
||||
return fixed_length_;
|
||||
}
|
||||
|
||||
inline uintptr_t GetFixedDataAddress() const
|
||||
{
|
||||
return ToUintPtr(&fixed_data_);
|
||||
}
|
||||
|
||||
inline JSTaggedType GetFixedBuffer(uint32_t idx) const
|
||||
{
|
||||
return fixed_data_[idx];
|
||||
@@ -188,6 +193,11 @@ private:
|
||||
return variable_length_;
|
||||
}
|
||||
|
||||
inline uintptr_t GetVariableDataAddress() const
|
||||
{
|
||||
return ToUintPtr(&variable_data_);
|
||||
}
|
||||
|
||||
inline JSTaggedType GetVariableBuffer(uint32_t idx) const
|
||||
{
|
||||
return variable_data_[idx];
|
||||
|
||||
@@ -222,30 +222,23 @@ bool FastRuntimeStub::ShouldCallSetter(JSTaggedValue receiver, JSTaggedValue hol
|
||||
return attr.IsWritable();
|
||||
}
|
||||
|
||||
JSTaggedValue FastRuntimeStub::AddPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
|
||||
JSTaggedValue value)
|
||||
PropertyAttributes FastRuntimeStub::AddPropertyByName(JSThread *thread, JSHandle<JSObject> objHandle,
|
||||
JSHandle<JSTaggedValue> keyHandle,
|
||||
JSHandle<JSTaggedValue> valueHandle,
|
||||
PropertyAttributes attr)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, AddPropertyByName);
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", JSTaggedValue::Exception());
|
||||
}
|
||||
|
||||
JSHandle<JSObject> objHandle(thread, receiver);
|
||||
JSHandle<JSTaggedValue> keyHandle(thread, key);
|
||||
JSHandle<JSTaggedValue> valueHandle(thread, value);
|
||||
if (objHandle->IsJSArray() && keyHandle.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString()) {
|
||||
objHandle->GetJSHClass()->SetHasConstructor(true);
|
||||
}
|
||||
PropertyAttributes attr = PropertyAttributes::Default();
|
||||
uint32_t unusedInlinedProps = objHandle->GetJSHClass()->GetUnusedInlinedProps();
|
||||
if (unusedInlinedProps != 0) {
|
||||
uint32_t order = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS - unusedInlinedProps;
|
||||
objHandle->SetPropertyInlinedProps(thread, order, value);
|
||||
attr.SetOffset(order);
|
||||
int32_t nextInlinedPropsIndex = objHandle->GetJSHClass()->GetNextInlinedPropsIndex();
|
||||
if (nextInlinedPropsIndex >= 0) {
|
||||
objHandle->SetPropertyInlinedProps(thread, nextInlinedPropsIndex, valueHandle.GetTaggedValue());
|
||||
attr.SetOffset(nextInlinedPropsIndex);
|
||||
attr.SetIsInlinedProps(true);
|
||||
JSHClass::AddProperty(thread, objHandle, keyHandle, attr);
|
||||
return JSTaggedValue::Undefined();
|
||||
return attr;
|
||||
}
|
||||
|
||||
JSMutableHandle<TaggedArray> array(thread, objHandle->GetProperties());
|
||||
@@ -260,19 +253,18 @@ JSTaggedValue FastRuntimeStub::AddPropertyByName(JSThread *thread, JSTaggedValue
|
||||
if (!array->IsDictionaryMode()) {
|
||||
attr.SetIsInlinedProps(false);
|
||||
|
||||
array_size_t outProps =
|
||||
JSHClass::DEFAULT_CAPACITY_OF_OUT_OBJECTS - objHandle->GetJSHClass()->GetUnusedNonInlinedProps();
|
||||
ASSERT(length >= outProps);
|
||||
array_size_t nonInlinedProps = objHandle->GetJSHClass()->GetNextNonInlinedPropsIndex();
|
||||
ASSERT(length >= nonInlinedProps);
|
||||
// if array is full, grow array or change to dictionary mode
|
||||
if (length == outProps) {
|
||||
if (UNLIKELY(length >= JSHClass::DEFAULT_CAPACITY_OF_OUT_OBJECTS)) {
|
||||
if (length == nonInlinedProps) {
|
||||
if (UNLIKELY(length == JSHClass::MAX_CAPACITY_OF_OUT_OBJECTS)) {
|
||||
// change to dictionary and add one.
|
||||
JSHandle<NameDictionary> dict(JSObject::TransitionToDictionary(thread, objHandle));
|
||||
attr.SetDictionaryOrder(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES);
|
||||
NameDictionary *newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
|
||||
objHandle->SetProperties(thread, JSTaggedValue(newDict));
|
||||
JSHandle<NameDictionary> newDict =
|
||||
NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr);
|
||||
objHandle->SetProperties(thread, newDict);
|
||||
// index is not essential when fastMode is false;
|
||||
return JSTaggedValue::Undefined();
|
||||
return attr;
|
||||
}
|
||||
// Grow properties array size
|
||||
array_size_t capacity = JSObject::ComputePropertyCapacity(length);
|
||||
@@ -281,15 +273,16 @@ JSTaggedValue FastRuntimeStub::AddPropertyByName(JSThread *thread, JSTaggedValue
|
||||
objHandle->SetProperties(thread, array.GetTaggedValue());
|
||||
}
|
||||
|
||||
attr.SetOffset(outProps + JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS);
|
||||
attr.SetOffset(nonInlinedProps + objHandle->GetJSHClass()->GetInlinedProperties());
|
||||
JSHClass::AddProperty(thread, objHandle, keyHandle, attr);
|
||||
array->Set(thread, outProps, valueHandle.GetTaggedValue());
|
||||
array->Set(thread, nonInlinedProps, valueHandle.GetTaggedValue());
|
||||
} else {
|
||||
JSHandle<NameDictionary> dictHandle(array);
|
||||
NameDictionary *newDict = NameDictionary::PutIfAbsent(thread, dictHandle, keyHandle, valueHandle, attr);
|
||||
objHandle->SetProperties(thread, JSTaggedValue(newDict));
|
||||
JSHandle<NameDictionary> newDict =
|
||||
NameDictionary::PutIfAbsent(thread, dictHandle, keyHandle, valueHandle, attr);
|
||||
objHandle->SetProperties(thread, newDict);
|
||||
}
|
||||
return JSTaggedValue::Undefined();
|
||||
return attr;
|
||||
}
|
||||
|
||||
JSTaggedValue FastRuntimeStub::AddPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
|
||||
@@ -396,9 +389,8 @@ JSTaggedValue FastRuntimeStub::GetPropertyByName(JSThread *thread, JSTaggedValue
|
||||
if (LIKELY(!hclass->IsDictionaryMode())) {
|
||||
ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
|
||||
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject());
|
||||
|
||||
int propsNumber = hclass->GetPropertiesNumber();
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
|
||||
int propsNumber = hclass->NumberOfProps();
|
||||
int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
|
||||
if (entry != -1) {
|
||||
PropertyAttributes attr(layoutInfo->GetAttr(entry));
|
||||
@@ -451,9 +443,9 @@ JSTaggedValue FastRuntimeStub::SetPropertyByName(JSThread *thread, JSTaggedValue
|
||||
if (LIKELY(!hclass->IsDictionaryMode())) {
|
||||
ASSERT(!TaggedArray::Cast(JSObject::Cast(holder)->GetProperties().GetTaggedObject())->IsDictionaryMode());
|
||||
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject());
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
|
||||
|
||||
int propsNumber = hclass->GetPropertiesNumber();
|
||||
int propsNumber = hclass->NumberOfProps();
|
||||
int entry = layoutInfo->FindElementWithCache(thread, hclass, key, propsNumber);
|
||||
if (entry != -1) {
|
||||
PropertyAttributes attr(layoutInfo->GetAttr(entry));
|
||||
@@ -504,7 +496,16 @@ JSTaggedValue FastRuntimeStub::SetPropertyByName(JSThread *thread, JSTaggedValue
|
||||
holder = hclass->GetPrototype();
|
||||
} while (holder.IsHeapObject());
|
||||
|
||||
return AddPropertyByName(thread, receiver, key, value);
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
JSHandle<JSObject> objHandle(thread, receiver);
|
||||
JSHandle<JSTaggedValue> keyHandle(thread, key);
|
||||
JSHandle<JSTaggedValue> valueHandle(thread, value);
|
||||
|
||||
if (UNLIKELY(!JSObject::Cast(receiver)->IsExtensible())) {
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot add property in prevent extensions ", JSTaggedValue::Exception());
|
||||
}
|
||||
AddPropertyByName(thread, objHandle, keyHandle, valueHandle, PropertyAttributes::Default());
|
||||
return JSTaggedValue::Undefined();
|
||||
}
|
||||
|
||||
template<bool UseOwn>
|
||||
@@ -622,11 +623,11 @@ bool FastRuntimeStub::FastSetPropertyByIndex(JSThread *thread, JSTaggedValue rec
|
||||
JSTaggedValue value)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, FastSetPropertyByIndex);
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT1
|
||||
auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(SetPropertyByIndex));
|
||||
typedef JSTaggedValue (*PFSetPropertyByIndex)(JSThread *, JSTaggedValue, uint32_t, JSTaggedValue);
|
||||
typedef JSTaggedValue (*PFSetPropertyByIndex)(uintptr_t, JSTaggedValue, uint32_t, JSTaggedValue);
|
||||
auto setPropertyByIndex = reinterpret_cast<PFSetPropertyByIndex>(stubAddr);
|
||||
JSTaggedValue result = setPropertyByIndex(thread, receiver, index, value);
|
||||
JSTaggedValue result = setPropertyByIndex(thread->GetGlueAddr(), receiver, index, value);
|
||||
#else
|
||||
JSTaggedValue result = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value);
|
||||
#endif
|
||||
@@ -661,11 +662,11 @@ JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedV
|
||||
// Maybe moved by GC
|
||||
receiver = receiverHandler.GetTaggedValue();
|
||||
}
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT1
|
||||
auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByName));
|
||||
typedef JSTaggedValue (*PFGetPropertyByName)(JSThread *, JSTaggedValue, JSTaggedValue);
|
||||
typedef JSTaggedValue (*PFGetPropertyByName)(uintptr_t, JSTaggedValue, JSTaggedValue);
|
||||
auto getPropertyByNamePtr = reinterpret_cast<PFGetPropertyByName>(stubAddr);
|
||||
JSTaggedValue result = getPropertyByNamePtr(thread, receiver, key);
|
||||
JSTaggedValue result = getPropertyByNamePtr(thread->GetGlueAddr(), receiver, key);
|
||||
#else
|
||||
JSTaggedValue result = FastRuntimeStub::GetPropertyByName(thread, receiver, key);
|
||||
#endif
|
||||
@@ -681,11 +682,11 @@ JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedV
|
||||
JSTaggedValue FastRuntimeStub::FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, FastGetPropertyByValue);
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT1
|
||||
auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByValue));
|
||||
typedef JSTaggedValue (*PFGetPropertyByValue)(JSThread *, JSTaggedValue, JSTaggedValue);
|
||||
typedef JSTaggedValue (*PFGetPropertyByValue)(uintptr_t, JSTaggedValue, JSTaggedValue);
|
||||
auto getPropertyByValuePtr = reinterpret_cast<PFGetPropertyByValue>(stubAddr);
|
||||
JSTaggedValue result = getPropertyByValuePtr(thread, receiver, key);
|
||||
JSTaggedValue result = getPropertyByValuePtr(thread->GetGlueAddr(), receiver, key);
|
||||
#else
|
||||
JSTaggedValue result = FastRuntimeStub::GetPropertyByValue(thread, receiver, key);
|
||||
#endif
|
||||
@@ -702,11 +703,11 @@ template<bool UseHole> // UseHole is only for Array::Sort() which requires Hole
|
||||
JSTaggedValue FastRuntimeStub::FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, FastGetPropertyByIndex);
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT
|
||||
#ifdef ECMASCRIPT_ENABLE_STUB_AOT1
|
||||
auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByIndex));
|
||||
typedef JSTaggedValue (*PFGetPropertyByIndex)(JSThread *, JSTaggedValue, uint32_t);
|
||||
typedef JSTaggedValue (*PFGetPropertyByIndex)(uintptr_t, JSTaggedValue, uint32_t);
|
||||
auto getPropertyByIndex = reinterpret_cast<PFGetPropertyByIndex>(stubAddr);
|
||||
JSTaggedValue result = getPropertyByIndex(thread, receiver, index);
|
||||
JSTaggedValue result = getPropertyByIndex(thread->GetGlueAddr(), receiver, index);
|
||||
#else
|
||||
JSTaggedValue result = FastRuntimeStub::GetPropertyByIndex(thread, receiver, index);
|
||||
#endif
|
||||
@@ -989,7 +990,7 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei
|
||||
JSHandle<JSTaggedValue> keyHandle(thread, key);
|
||||
JSHandle<JSTaggedValue> valHandle(thread, value);
|
||||
JSHandle<JSObject> objHandle(thread, obj);
|
||||
JSHandle<GlobalDictionary> dictHandle(thread, GlobalDictionary::Create(thread));
|
||||
JSHandle<GlobalDictionary> dictHandle(GlobalDictionary::Create(thread));
|
||||
|
||||
// Add PropertyBox to global dictionary
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
@@ -998,9 +999,9 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei
|
||||
PropertyBoxType boxType = valHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT;
|
||||
attr.SetBoxType(boxType);
|
||||
|
||||
GlobalDictionary *properties =
|
||||
JSHandle<GlobalDictionary> properties =
|
||||
GlobalDictionary::PutIfAbsent(thread, dictHandle, keyHandle, JSHandle<JSTaggedValue>(boxHandle), attr);
|
||||
objHandle->SetProperties(thread, JSTaggedValue(properties));
|
||||
objHandle->SetProperties(thread, properties);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1048,9 +1049,9 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei
|
||||
PropertyBoxType boxType = valHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT;
|
||||
attr.SetBoxType(boxType);
|
||||
|
||||
GlobalDictionary *properties =
|
||||
JSHandle<GlobalDictionary> properties =
|
||||
GlobalDictionary::PutIfAbsent(thread, dictHandle, keyHandle, JSHandle<JSTaggedValue>(boxHandle), attr);
|
||||
objHandle->SetProperties(thread, JSTaggedValue(properties));
|
||||
objHandle->SetProperties(thread, properties);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1177,10 +1178,10 @@ JSTaggedValue FastRuntimeStub::FindOwnProperty(JSThread *thread, JSObject *obj,
|
||||
INTERPRETER_TRACE(thread, FindOwnProperty);
|
||||
if (!properties->IsDictionaryMode()) {
|
||||
JSHClass *cls = obj->GetJSHClass();
|
||||
JSTaggedValue attrs = cls->GetAttributes();
|
||||
JSTaggedValue attrs = cls->GetLayout();
|
||||
if (!attrs.IsNull()) {
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetHeapObject());
|
||||
int propNumber = cls->GetPropertiesNumber();
|
||||
int propNumber = cls->NumberOfProps();
|
||||
int entry = layoutInfo->FindElementWithCache(thread, cls, key, propNumber);
|
||||
if (entry != -1) {
|
||||
*attr = layoutInfo->GetAttr(entry);
|
||||
@@ -1189,7 +1190,7 @@ JSTaggedValue FastRuntimeStub::FindOwnProperty(JSThread *thread, JSObject *obj,
|
||||
if (attr->IsInlinedProps()) {
|
||||
return obj->GetPropertyInlinedProps(entry);
|
||||
}
|
||||
*indexOrEntry -= JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS;
|
||||
*indexOrEntry -= cls->GetInlinedProperties();
|
||||
return properties->Get(*indexOrEntry);
|
||||
}
|
||||
}
|
||||
@@ -1250,16 +1251,16 @@ JSTaggedValue FastRuntimeStub::FindOwnProperty(JSThread *thread, JSObject *obj,
|
||||
TaggedArray *array = TaggedArray::Cast(obj->GetProperties().GetHeapObject());
|
||||
if (!array->IsDictionaryMode()) {
|
||||
JSHClass *cls = obj->GetJSHClass();
|
||||
JSTaggedValue attrs = cls->GetAttributes();
|
||||
JSTaggedValue attrs = cls->GetLayout();
|
||||
if (!attrs.IsNull()) {
|
||||
LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetHeapObject());
|
||||
int propsNumber = cls->GetPropertiesNumber();
|
||||
int propsNumber = cls->NumberOfProps();
|
||||
int entry = layoutInfo->FindElementWithCache(thread, cls, key, propsNumber);
|
||||
if (entry != -1) {
|
||||
PropertyAttributes attr(layoutInfo->GetAttr(entry));
|
||||
ASSERT(static_cast<int>(attr.GetOffset()) == entry);
|
||||
return attr.IsInlinedProps() ? obj->GetPropertyInlinedProps(entry)
|
||||
: array->Get(entry - JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS);
|
||||
: array->Get(entry - cls->GetInlinedProperties());
|
||||
}
|
||||
}
|
||||
return JSTaggedValue::Hole(); // array == empty array will return here.
|
||||
|
||||
@@ -92,6 +92,10 @@ public:
|
||||
static inline JSTaggedValue FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key);
|
||||
template<bool UseHole = false>
|
||||
static inline JSTaggedValue FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index);
|
||||
static inline PropertyAttributes AddPropertyByName(JSThread *thread, JSHandle<JSObject> objHandle,
|
||||
JSHandle<JSTaggedValue> keyHandle,
|
||||
JSHandle<JSTaggedValue> valueHandle,
|
||||
PropertyAttributes attr);
|
||||
|
||||
private:
|
||||
friend class ICRuntimeStub;
|
||||
@@ -104,8 +108,6 @@ private:
|
||||
JSTaggedValue accessorValue);
|
||||
static inline bool ShouldCallSetter(JSTaggedValue receiver, JSTaggedValue holder, JSTaggedValue accessorValue,
|
||||
PropertyAttributes attr);
|
||||
static inline JSTaggedValue AddPropertyByName(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key,
|
||||
JSTaggedValue value);
|
||||
static inline JSTaggedValue AddPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index,
|
||||
JSTaggedValue value);
|
||||
};
|
||||
|
||||
Regular → Executable
+39
-31
@@ -14,9 +14,14 @@
|
||||
*/
|
||||
|
||||
#include "ecmascript/interpreter/frame_handler.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "libpandafile/bytecode_instruction-inl.h"
|
||||
|
||||
#include "ecmascript/class_linker/program_object.h"
|
||||
#include "ecmascript/compiler/llvm/llvm_stackmap_parser.h"
|
||||
#include "ecmascript/mem/heap.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
|
||||
#include "libpandafile/bytecode_instruction-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
void FrameHandler::PrevFrame()
|
||||
@@ -63,7 +68,7 @@ void InterpretedFrameHandler::PrevFrame()
|
||||
void InterpretedFrameHandler::PrevInterpretedFrame()
|
||||
{
|
||||
FrameHandler::PrevFrame();
|
||||
for (;HasFrame() && GetFrameType() != FrameType::INTERPRETER_FRAME; FrameHandler::PrevFrame());
|
||||
for (; HasFrame() && GetFrameType() != FrameType::INTERPRETER_FRAME; FrameHandler::PrevFrame());
|
||||
}
|
||||
|
||||
InterpretedFrameHandler InterpretedFrameHandler::GetPrevFrame() const
|
||||
@@ -112,8 +117,8 @@ uint32_t InterpretedFrameHandler::GetBytecodeOffset() const
|
||||
ASSERT(HasFrame());
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
FrameState *state = reinterpret_cast<FrameState *>(sp_) - 1;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
auto offset = state->pc - JSMethod::Cast(state->method)->GetBytecodeArray();
|
||||
JSMethod *method = ECMAObject::Cast(state->function.GetTaggedObject())->GetCallTarget();
|
||||
auto offset = state->pc - method->GetBytecodeArray();
|
||||
return static_cast<uint32_t>(offset);
|
||||
}
|
||||
|
||||
@@ -122,7 +127,7 @@ JSMethod *InterpretedFrameHandler::GetMethod() const
|
||||
ASSERT(HasFrame());
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
FrameState *state = reinterpret_cast<FrameState *>(sp_) - 1;
|
||||
return state->method;
|
||||
return ECMAObject::Cast(state->function.GetTaggedObject())->GetCallTarget();
|
||||
}
|
||||
|
||||
JSTaggedValue InterpretedFrameHandler::GetFunction() const
|
||||
@@ -130,10 +135,7 @@ JSTaggedValue InterpretedFrameHandler::GetFunction() const
|
||||
ASSERT(HasFrame());
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
FrameState *state = reinterpret_cast<FrameState *>(sp_) - 1;
|
||||
uint32_t numVregs = state->method->GetNumVregs();
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
auto func = JSTaggedValue(sp_[numVregs]);
|
||||
return func;
|
||||
return state->function;
|
||||
}
|
||||
|
||||
const uint8_t *InterpretedFrameHandler::GetPc() const
|
||||
@@ -157,7 +159,7 @@ ConstantPool *InterpretedFrameHandler::GetConstpool() const
|
||||
ASSERT(HasFrame());
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
FrameState *state = reinterpret_cast<FrameState *>(sp_) - 1;
|
||||
return state->constpool;
|
||||
return ConstantPool::Cast(state->constpool.GetTaggedObject());
|
||||
}
|
||||
|
||||
JSTaggedValue InterpretedFrameHandler::GetEnv() const
|
||||
@@ -181,6 +183,7 @@ void InterpretedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisi
|
||||
FrameState *prev_state = reinterpret_cast<FrameState *>(state->base.prev) - 1;
|
||||
uintptr_t end = ToUintPtr(prev_state);
|
||||
v1(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end));
|
||||
v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&state->function)));
|
||||
if (state->pc != nullptr) {
|
||||
// interpreter frame
|
||||
v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&state->acc)));
|
||||
@@ -220,24 +223,21 @@ void OptimizedFrameHandler::PrevFrame()
|
||||
sp_ = reinterpret_cast<JSTaggedType *>(state->prev);
|
||||
}
|
||||
|
||||
void OptimizedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const
|
||||
void OptimizedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1,
|
||||
ChunkVector<DerivedData> *derivedPointers, bool isVerifying) const
|
||||
{
|
||||
uintptr_t *current = fp_;
|
||||
if (current != nullptr) {
|
||||
if (fp_ != nullptr) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
std::set<uintptr_t> slotAddrs;
|
||||
auto returnAddr = reinterpret_cast<uintptr_t>(*(current + 1));
|
||||
LOG_ECMA(INFO) << __FUNCTION__ << " returnAddr :" << returnAddr << std::endl;
|
||||
auto returnAddr = reinterpret_cast<uintptr_t>(*(fp_ + 1));
|
||||
bool ret = kungfu::LLVMStackMapParser::GetInstance().StackMapByFuncAddrFp(
|
||||
returnAddr,
|
||||
reinterpret_cast<uintptr_t>(fp_),
|
||||
slotAddrs);
|
||||
returnAddr, reinterpret_cast<uintptr_t>(fp_), v0, v1, derivedPointers, isVerifying);
|
||||
if (ret == false) {
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(DEBUG) << " stackmap don't found returnAddr " << returnAddr;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
for (auto &address: slotAddrs) {
|
||||
v0(Root::ROOT_FRAME, ObjectSlot(address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,8 @@ void OptimizedEntryFrameHandler::PrevFrame()
|
||||
sp_ = reinterpret_cast<JSTaggedType *>(state->threadFp);
|
||||
}
|
||||
|
||||
void FrameIterator::HandleRuntimeTrampolines(const RootVisitor &v0, const RootRangeVisitor &v1) const
|
||||
void FrameIterator::HandleRuntimeTrampolines(const RootVisitor &v0, const RootRangeVisitor &v1,
|
||||
ChunkVector<DerivedData> *derivedPointers, bool isVerifying) const
|
||||
{
|
||||
if (thread_) {
|
||||
uintptr_t *fp = thread_->GetLastOptCallRuntimePc();
|
||||
@@ -258,12 +259,13 @@ void FrameIterator::HandleRuntimeTrampolines(const RootVisitor &v0, const RootRa
|
||||
std::set<uintptr_t> slotAddrs;
|
||||
auto returnAddr = *(fp + 1);
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << __FUNCTION__ << " returnAddr :" << returnAddr << " fp: " << fp << std::endl;
|
||||
uintptr_t *optFp = reinterpret_cast<uintptr_t *>(*fp);
|
||||
auto type = *(optFp - 1);
|
||||
LOG_ECMA(INFO) << __FUNCTION__ << " returnAddr :" << std::hex << returnAddr << " fp: " << fp << " type:" <<
|
||||
static_cast<uint64_t>(type) << std::endl;
|
||||
#endif
|
||||
bool ret = kungfu::LLVMStackMapParser::GetInstance().StackMapByFuncAddrFp(
|
||||
reinterpret_cast<uintptr_t>(returnAddr),
|
||||
reinterpret_cast<uintptr_t>(fp),
|
||||
slotAddrs);
|
||||
returnAddr, reinterpret_cast<uintptr_t>(fp), v0, v1, derivedPointers, isVerifying);
|
||||
if (ret == false) {
|
||||
#ifndef NDEBUG
|
||||
LOG_ECMA(INFO) << " stackmap don't found returnAddr " << std::endl;
|
||||
@@ -282,13 +284,19 @@ void FrameIterator::HandleRuntimeTrampolines(const RootVisitor &v0, const RootRa
|
||||
|
||||
void FrameIterator::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const
|
||||
{
|
||||
JSTaggedType *current = fp_;
|
||||
ChunkVector<DerivedData> *derivedPointers = thread_->GetEcmaVM()->GetHeap()->GetDerivedPointers();
|
||||
bool isVerifying = false;
|
||||
|
||||
#if ECMASCRIPT_ENABLE_HEAP_VERIFY
|
||||
isVerifying = thread_->GetEcmaVM()->GetHeap()->GetIsVerifying();
|
||||
#endif
|
||||
// handle runtimeTrampolines Frame in order get stub returnAddress which used by
|
||||
// stackMap
|
||||
HandleRuntimeTrampolines(v0, v1);
|
||||
HandleRuntimeTrampolines(v0, v1, derivedPointers, isVerifying);
|
||||
|
||||
JSTaggedType *current = fp_;
|
||||
while (current) {
|
||||
FrameType type = FrameHandler(current).GetFrameType();
|
||||
LOG_ECMA(INFO) << __FUNCTION__ << "type = " << static_cast<uint64_t>(type) << std::endl;
|
||||
if (type == FrameType::INTERPRETER_FRAME) {
|
||||
FrameState *state = reinterpret_cast<FrameState *>(current) - 1;
|
||||
InterpretedFrameHandler(current).Iterate(v0, v1);
|
||||
@@ -297,7 +305,7 @@ void FrameIterator::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) c
|
||||
OptimizedFrameStateBase *state = reinterpret_cast<OptimizedFrameStateBase *>(
|
||||
reinterpret_cast<intptr_t>(current) -
|
||||
MEMBER_OFFSET(OptimizedFrameStateBase, prev));
|
||||
OptimizedFrameHandler(reinterpret_cast<uintptr_t *>(current)).Iterate(v0, v1);
|
||||
OptimizedFrameHandler(reinterpret_cast<uintptr_t *>(current)).Iterate(v0, v1, derivedPointers, isVerifying);
|
||||
current = reinterpret_cast<JSTaggedType *>(state->prev);
|
||||
} else {
|
||||
ASSERT(type == FrameType::OPTIMIZED_ENTRY_FRAME);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user