!265 sync code to ohos master

Merge pull request !265 from zhangyukun8/master
This commit is contained in:
openharmony_ci
2021-12-21 07:31:25 +00:00
committed by Gitee
298 changed files with 21888 additions and 9940 deletions
+26 -16
View File
@@ -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"
+1
View File
@@ -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
+1
View File
@@ -28,6 +28,7 @@
│ ├─ builtins # ECMAScript标准库
│ ├─ class_linker # 字节码预处理模块
│ ├─ compiler # JS编译器
│ ├─ cpu_profiler # CPU性能分析器
│ ├─ hprof # 内存分析工具
│ ├─ ic # 内联缓存模块
│ ├─ interpreter # JS解释器
+33 -2
View File
@@ -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
+7 -7
View File
@@ -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));
+3 -2
View File
@@ -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());
+1 -1
View File
@@ -44,7 +44,7 @@ JSTaggedValue BuiltinsMap::MapConstructor(EcmaRuntimeCallInfo *argv)
JSHandle<JSMap> map = JSHandle<JSMap>::Cast(obj);
// 4.Set maps [[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.
+14 -10
View File
@@ -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)
+7 -1
View File
@@ -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();
}
+123 -87
View File
@@ -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)
{
+19 -4
View File
@@ -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> &regexp);
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;
+2 -2
View File
@@ -46,7 +46,7 @@ JSTaggedValue BuiltinsSet::SetConstructor(EcmaRuntimeCallInfo *argv)
JSHandle<JSSet> set = JSHandle<JSSet>::Cast(obj);
// 3.ReturnIfAbrupt(set).
// 4.Set sets [[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();
+1 -1
View File
@@ -45,7 +45,7 @@ JSTaggedValue BuiltinsWeakMap::WeakMapConstructor(EcmaRuntimeCallInfo *argv)
JSHandle<JSWeakMap> weakMap = JSHandle<JSWeakMap>::Cast(obj);
// 4.Set weakmaps [[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.
+1 -1
View File
@@ -45,7 +45,7 @@ JSTaggedValue BuiltinsWeakSet::WeakSetConstructor(EcmaRuntimeCallInfo *argv)
JSHandle<JSWeakSet> weakSet = JSHandle<JSWeakSet>::Cast(obj);
// 3.ReturnIfAbrupt(weakSet).
// 4.WeakSet sets [[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:
+2 -2
View File
@@ -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",
+49 -41
View File
@@ -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();
}
+31 -31
View File
@@ -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;
+166 -137
View File
@@ -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
+53 -37
View File
@@ -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_;
};
+3 -3
View File
@@ -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
+2 -2
View File
@@ -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
File diff suppressed because it is too large Load Diff
+284 -113
View File
@@ -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
+48 -21
View File
@@ -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
View File
@@ -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
View File
@@ -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
-125
View File
@@ -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;
+928
View File
@@ -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();
+229 -229
View File
@@ -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
+320 -277
View File
@@ -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
+39 -16
View File
@@ -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
+92 -55
View File
@@ -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
+15 -15
View File
@@ -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
+28 -28
View File
@@ -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;
+8 -8
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+370 -1288
View File
File diff suppressed because it is too large Load Diff
+238 -204
View File
@@ -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
+19 -1
View File
@@ -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};
};
+1 -1
View File
@@ -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,
]
}
+204 -196
View File
@@ -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
+22
View File
@@ -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
+56
View File
@@ -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
+9 -4
View File
@@ -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 {
+59 -33
View File
@@ -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;
}
+16 -16
View File
@@ -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
+256
View File
@@ -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 &currentProcessInfo) 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
+77
View File
@@ -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 &currentProcessInfo) 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
View File
@@ -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;
+153 -36
View File
@@ -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
+176 -32
View File
@@ -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
+4
View File
@@ -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());
+4
View File
@@ -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]
+73 -3
View File
@@ -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
View File
@@ -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 &currentPathFile, 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 &currentPathFile
}
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
+5 -20
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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>(&regexpCache_));
}
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
View File
@@ -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
+1
View File
@@ -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));
+1
View File
@@ -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) \
+1 -1
View File
@@ -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 =
+3 -2
View File
@@ -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);
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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) {
+2 -2
View File
@@ -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);
+1 -1
View File
@@ -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"
+359
View File
@@ -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_
+62
View File
@@ -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_
+478
View File
@@ -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
+78
View File
@@ -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
+2 -2
View File
@@ -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));
}
+2 -1
View File
@@ -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);
}
}
+174
View File
@@ -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
+48
View File
@@ -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_
-1
View File
@@ -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;
+1 -1
View File
@@ -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
+121
View File
@@ -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",
]
}
+384
View File
@@ -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
+463
View File
@@ -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
+134
View File
@@ -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());
}
}
+7 -8
View File
@@ -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));
}
+10
View File
@@ -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];
+60 -59
View File
@@ -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.
+4 -2
View File
@@ -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);
};
+39 -31
View File
@@ -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