mirror of
https://github.com/openharmony/ark_runtime_core.git
synced 2026-07-01 13:17:23 -04:00
add ark runtime_core
Signed-off-by: wanyanglan <wanyanglan1@huawei.com> Change-Id: I2564094cef9c6c41263e37faf9ffbbec14223dc7
This commit is contained in:
+126
@@ -0,0 +1,126 @@
|
||||
# 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.
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
# 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.
|
||||
---
|
||||
# Note well! The list of global exceptions is maintained in cmake/ClangTidy.cmake
|
||||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: '.*/(assembler|compiler|debugger|libpandabase|libpandafile|runtime|class2panda)/.*'
|
||||
AnalyzeTemporaryDtors: false
|
||||
User: user
|
||||
CheckOptions:
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '1'
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||
value: '10'
|
||||
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||
value: '2'
|
||||
- key: modernize-loop-convert.MaxCopySize
|
||||
value: '16'
|
||||
- key: modernize-loop-convert.MinConfidence
|
||||
value: reasonable
|
||||
- key: modernize-loop-convert.NamingStyle
|
||||
value: CamelCase
|
||||
- key: modernize-pass-by-value.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-nullptr.NullMacros
|
||||
value: 'NULL'
|
||||
- key: readability-identifier-naming.ClassMethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.MethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.EnumConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.ConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.ConstantMemberCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-function-size.LineThreshold
|
||||
value: 200
|
||||
- key: readability-identifier-naming.NamespaceCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ClassCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.PrivateMemberSuffix
|
||||
value: _
|
||||
- key: readability-identifier-naming.StructCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.VariableCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.GlobalConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.GlobalConstantPrefix
|
||||
value: g_
|
||||
- key: readability-identifier-naming.LocalVariableCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ParameterCase
|
||||
value: lower_case
|
||||
- key: readability-magic-numbers.IgnoredIntegerValues
|
||||
value: '1;2;3;4;5;6;7;8'
|
||||
...
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#Set defaul end of lines for all files
|
||||
* text eol=lf
|
||||
# Denote all image files as binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.gif binary
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/ark-third-party
|
||||
**/compile_commands.json
|
||||
/build**
|
||||
build_*
|
||||
/out/
|
||||
.vscode
|
||||
.idea
|
||||
*cmake-build-*
|
||||
cts-generated
|
||||
.dir-locals.el
|
||||
artifacts/
|
||||
cscope*
|
||||
tags
|
||||
.byebug_history
|
||||
.cache
|
||||
*.swp
|
||||
@@ -0,0 +1,19 @@
|
||||
# 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.
|
||||
|
||||
buildconfig = "//build/config/BUILDCONFIG.gn"
|
||||
|
||||
secondary_source = "//gn"
|
||||
script_executable = "/usr/bin/env"
|
||||
|
||||
exec_script("//scripts/install-third-party")
|
||||
@@ -0,0 +1,135 @@
|
||||
Aleksandr Emelenko
|
||||
Aleksandr Lovkov
|
||||
Aleksandr Popov
|
||||
Aleksei Grebenkin
|
||||
Aleksei Sidorov
|
||||
Alexander Semenov
|
||||
Alexey Biryukov
|
||||
Alexey Romanov
|
||||
Alina Kropacheva
|
||||
Anna Antipina
|
||||
Anton Makarenko
|
||||
Anton Romanov
|
||||
Anton Soldatov
|
||||
Anton Youdkevitch
|
||||
Artem Udovichenko
|
||||
Boris Molodenkov
|
||||
Boris Ulasevich
|
||||
Chen Mudan
|
||||
Chen Qiuyao
|
||||
Chen Tingwei
|
||||
Csaba Osztrogonac
|
||||
Cui Guihua
|
||||
Dai Huina
|
||||
Daniil Kochergin
|
||||
Daniil Kofanov
|
||||
Denis Kononenko
|
||||
Denis Krylov
|
||||
Denis Slynko
|
||||
Denis Tomashev
|
||||
Denis Zakharov
|
||||
Ding Ding
|
||||
Ding Wen
|
||||
Dmitrii Trubenkov
|
||||
Dmitry Alexeev
|
||||
Dmitry Bubnov
|
||||
Dmitry Buzmakov
|
||||
Dmitry Chuyko
|
||||
Dmitry Kovalenko
|
||||
Dmitry Pochepko
|
||||
Dong Kaixing
|
||||
Evgenii Kudriashov
|
||||
Evgeny Gavrin
|
||||
Filipp Zhinkin
|
||||
Gan Lan
|
||||
Ge Tingke
|
||||
Gong Junsong
|
||||
Guo Bingbing
|
||||
Hao Tuo
|
||||
Hu Feng
|
||||
Hu Xiaowei
|
||||
Huang Feijie
|
||||
Huang Haitao
|
||||
Huang Huijin
|
||||
Huang Yu
|
||||
Igor Gorban
|
||||
Igor Petrov
|
||||
Ilya Trubachev
|
||||
Ivan Burimskii
|
||||
Ivan Trubachev
|
||||
Ji Andong
|
||||
Jiang Han
|
||||
Kirill Galitskiy
|
||||
Konstantin Baladurin
|
||||
Konstantin Nazarov
|
||||
Leonid Dyachkov
|
||||
Li Chenshuai
|
||||
Li Wentao
|
||||
Li Yiming
|
||||
Li Yongbiao
|
||||
Lin Xiang
|
||||
Liu Xin
|
||||
Lu Kai
|
||||
Luo Chuhao
|
||||
Maria Filippova
|
||||
Mark Gonopolskiy
|
||||
Martin Negyorku
|
||||
Maxim Bolshov
|
||||
Maxim Morozov
|
||||
Maxim Zimnyukov
|
||||
Mikhail Aksenov
|
||||
Mikhail Chernov
|
||||
Mikhail Kaskov
|
||||
Mikhail Redkin
|
||||
Mikhail Sherstennikov
|
||||
Mikita Strizhak
|
||||
Nikita Kharitonov
|
||||
Nikita Sizov
|
||||
Pan Zhengyu
|
||||
Pang Desong
|
||||
Pavel Andrianov
|
||||
Pavel Ishin
|
||||
Pei Jiajun
|
||||
Peng Biao
|
||||
Qiu Yu
|
||||
Robert Fancsik
|
||||
Roland Takacs
|
||||
Roman Zhuykov
|
||||
Sergei Shadrin
|
||||
Sergey Chernykh
|
||||
Sergey Goldenberg
|
||||
Sergey Nikitin
|
||||
Stepan Dyatkovskiy
|
||||
Su Chongwei
|
||||
Sun Zhe
|
||||
Vadim Mutilin
|
||||
Vadim Sofin
|
||||
Vasil Dyadov
|
||||
Vasily Isaenko
|
||||
Vasily Kopyl
|
||||
Viktor Kutuzov
|
||||
Vitalii Mordan
|
||||
Vladimir Kuznetsov
|
||||
Vladimir Popov
|
||||
Vsevolod Pukhov
|
||||
Vyacheslav Cherkashin
|
||||
Wan Yanglan
|
||||
Wang Gang
|
||||
Wang Yaofeng
|
||||
Wang Zhaoyong
|
||||
Weng Changcheng
|
||||
Wu Pengyong
|
||||
Wu Zhefeng
|
||||
Xian Yuqiang
|
||||
Xiong Luo
|
||||
Xu Cheng
|
||||
Xu Jie
|
||||
Yan Churkin
|
||||
Ye Xiangrun
|
||||
Ying Guofeng
|
||||
Yu Jianchao
|
||||
Zhang Quan
|
||||
Zhang Rengao
|
||||
Zhang Yukun
|
||||
Zhao Gaoyi
|
||||
Zheng Jiahuan
|
||||
@@ -0,0 +1,150 @@
|
||||
# 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/runtime_core/ark_config.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
group("ark_packages") {
|
||||
if (host_os != "mac") {
|
||||
deps = [
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"$ark_root/libpandafile:libarkfile",
|
||||
"$ark_root/libziparchive:libarkziparchive",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_linux_tools_packages") {
|
||||
if (host_os != "mac") {
|
||||
deps = [
|
||||
"$ark_root/assembler:ark_asm(${host_toolchain})",
|
||||
"$ark_root/disassembler:ark_disasm(${host_toolchain})",
|
||||
"$ark_root/libpandabase:libarkbase(${host_toolchain})",
|
||||
"$ark_root/libpandafile:libarkfile(${host_toolchain})",
|
||||
"$ark_root/libziparchive:libarkziparchive(${host_toolchain})",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_windows_tools_packages") {
|
||||
if (host_os != "mac" && !ark_standalone_build) {
|
||||
deps = [
|
||||
"$ark_root/assembler:ark_asm(//build/toolchain/mingw:mingw_x86_64)",
|
||||
"$ark_root/disassembler:ark_disasm(//build/toolchain/mingw:mingw_x86_64)",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_mac_tools_packages") {
|
||||
if (host_os == "mac") {
|
||||
deps = [
|
||||
"$ark_root/assembler:ark_asm(//build/toolchain/mac:clang_x64)",
|
||||
"$ark_root/disassembler:ark_disasm(//build/toolchain/mac:clang_x64)",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# Common config for ark source
|
||||
config("ark_config") {
|
||||
if (!ark_standalone_build) {
|
||||
visibility = [ ":*" ]
|
||||
}
|
||||
|
||||
include_dirs = [ "$ark_root" ]
|
||||
defines = [ "PANDA_ENABLE_LTO" ]
|
||||
|
||||
if (is_linux) {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_TARGET_LINUX",
|
||||
"PANDA_USE_FUTEX",
|
||||
]
|
||||
} else if (is_mingw) {
|
||||
defines += [
|
||||
"PANDA_TARGET_WINDOWS",
|
||||
"_CRTBLD",
|
||||
"__LIBMSVCRT__",
|
||||
]
|
||||
} else if (is_mac) {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_TARGET_MACOS",
|
||||
"PANDA_USE_FUTEX",
|
||||
]
|
||||
} else {
|
||||
defines += [ "PANDA_TARGET_UNIX", "PANDA_USE_FUTEX", ]
|
||||
if (!is_standard_system && (current_cpu != "arm" || is_wearable_product)) {
|
||||
defines += [
|
||||
"PANDA_TARGET_MOBILE",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_debug) {
|
||||
defines += [ "NDEBUG" ]
|
||||
}
|
||||
|
||||
cflags_cc = [
|
||||
"-std=c++17",
|
||||
"-pedantic",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-Wshadow",
|
||||
"-fno-rtti",
|
||||
"-fno-exceptions",
|
||||
"-Wno-invalid-offsetof",
|
||||
|
||||
"-Wno-gnu-statement-expression",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-result",
|
||||
]
|
||||
|
||||
if (!is_mac && use_pbqp) {
|
||||
cflags_cc += [
|
||||
# PBQP regalloc
|
||||
"-mllvm",
|
||||
"-regalloc=pbqp",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_debug) {
|
||||
cflags_cc += [
|
||||
"-Og",
|
||||
"-ggdb3",
|
||||
]
|
||||
}
|
||||
|
||||
if (current_cpu == "arm") {
|
||||
defines += [
|
||||
"PANDA_TARGET_ARM32_ABI_SOFT=1",
|
||||
"PANDA_TARGET_ARM32",
|
||||
]
|
||||
} else if (current_cpu == "arm64") {
|
||||
defines += [
|
||||
"PANDA_TARGET_ARM64",
|
||||
"PANDA_TARGET_64",
|
||||
"PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES",
|
||||
"PANDA_USE_32_BIT_POINTER",
|
||||
]
|
||||
} else if (current_cpu == "x86") {
|
||||
defines += [ "PANDA_TARGET_X86" ]
|
||||
} else if (current_cpu == "amd64" || current_cpu == "x64" ||
|
||||
current_cpu == "x86_64") {
|
||||
defines += [
|
||||
"PANDA_TARGET_64",
|
||||
"PANDA_TARGET_AMD64",
|
||||
"PANDA_USE_32_BIT_POINTER",
|
||||
]
|
||||
}
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
project(PANDA NONE)
|
||||
|
||||
# Add our custom configuration types to
|
||||
# multi-configuration generators (i.e. Visual Studio):
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
list(APPEND CMAKE_CONFIGURATION_TYPES "FastVerify" "DebugDetailed")
|
||||
list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}
|
||||
CACHE STRING "CMake configuration types" FORCE)
|
||||
endif()
|
||||
|
||||
enable_language(CXX ASM)
|
||||
|
||||
# NB! For God's sake do not touch the command below.
|
||||
# See https://gitlab.kitware.com/cmake/cmake/issues/16588.
|
||||
# and https://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# ----- Default flags ----------------------------------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# ----- Global variables -------------------------------------------------------
|
||||
# Please don't use CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR to allow building
|
||||
# Panda as a cmake subdirectory. You can use the following variables if you
|
||||
# need to refer the Panda root directories
|
||||
set(PANDA_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(PANDA_BINARY_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(PANDA_THIRD_PARTY_SOURCES_DIR ${PANDA_ROOT}/ark-third-party)
|
||||
set(PANDA_THIRD_PARTY_CONFIG_DIR ${PANDA_ROOT}/cmake/ark-third-party)
|
||||
|
||||
# ----- Platform definitions ---------------------------------------------------
|
||||
include(cmake/Definitions.cmake)
|
||||
|
||||
if (NOT "${CMAKE_BUILD_TYPE}" MATCHES "Release" AND NOT PANDA_TARGET_WINDOWS)
|
||||
# Needed for stacktrace printing
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror -Wshadow")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
|
||||
if(PANDA_TARGET_MACOS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.13")
|
||||
endif()
|
||||
|
||||
set(PANDA_PGO_PROFGEN_PATH "/data/local/tmp")
|
||||
|
||||
if (PANDA_TARGET_MOBILE AND (PANDA_TARGET_ARM64 OR PANDA_TARGET_ARM32))
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")
|
||||
endif()
|
||||
|
||||
if (PANDA_PGO_INSTRUMENT)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}")
|
||||
endif()
|
||||
|
||||
if (PANDA_PGO_OPTIMIZE)
|
||||
if (NOT PANDA_PGO_PROFILE_DATA)
|
||||
message(FATAL_ERROR "PANDA_PGO_PROFILE_DATA is not set")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}")
|
||||
endif()
|
||||
|
||||
if (PANDA_ENABLE_LTO)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=thin")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto=thin")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto=thin")
|
||||
endif()
|
||||
|
||||
if (PANDA_LLVM_REGALLOC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -regalloc=${PANDA_LLVM_REGALLOC}")
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
|
||||
add_compile_options(-O2 -ggdb3 -fno-omit-frame-pointer)
|
||||
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "FastVerify")
|
||||
add_compile_options(-O2 -ggdb3)
|
||||
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "DebugDetailed")
|
||||
add_compile_options(-Og -ggdb3)
|
||||
endif()
|
||||
|
||||
if (PANDA_THREAD_SAFETY)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wthread-safety")
|
||||
endif()
|
||||
|
||||
if (PANDA_ARK_JS_VM)
|
||||
add_definitions(-DPANDA_ARK_JS_VM)
|
||||
endif()
|
||||
|
||||
# ----- Deliverable executables and libraries ----------------------------------
|
||||
# Please override with per-target properties if your artifact should reside
|
||||
# elsewhere, like this:
|
||||
# set_target_properties(... PROPERTIES RUNTIME_OUTPUT_DIRECTORY ...)
|
||||
# Applicable for tests and all "internal" artifacts.
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/bin)
|
||||
|
||||
# ----- Panda CMake functions --------------------------------------------------
|
||||
include(cmake/PandaCmakeFunctions.cmake)
|
||||
|
||||
# ----- Bootstrapping (for parts of platform written in managed code ) ---------
|
||||
include(cmake/HostTools.cmake)
|
||||
|
||||
# ----- Enable CCache ----------------------------------------------------------
|
||||
include(cmake/PandaCCache.cmake)
|
||||
|
||||
# ----- Code analysis and style ------------------------------------------------
|
||||
include(cmake/ClangTidy.cmake)
|
||||
include(cmake/CodeStyle.cmake)
|
||||
|
||||
# ----- Sanitizers testing -----------------------------------------------------
|
||||
include(cmake/Sanitizers.cmake)
|
||||
|
||||
# ----- Enable testing ---------------------------------------------------------
|
||||
|
||||
# Umbrella target for testing:
|
||||
add_custom_target(tests COMMENT "Running all test suites")
|
||||
|
||||
include(cmake/Testing.cmake)
|
||||
|
||||
# ----- Template Based Generator -----------------------------------------------
|
||||
include(cmake/TemplateBasedGen.cmake)
|
||||
|
||||
# ----- Enable panda assemblies building ---------------------------------------
|
||||
include(cmake/PandaAssembly.cmake)
|
||||
|
||||
# Some compilers use x87 fp instructions by default in 32-bit mode.
|
||||
# We need to use SSE one to correspond x86_64 build.
|
||||
if (PANDA_TARGET_X86)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse3")
|
||||
endif()
|
||||
|
||||
# ----- Targets ----------------------------------------------------------------
|
||||
|
||||
execute_process(COMMAND ${PANDA_ROOT}/scripts/install-third-party
|
||||
WORKING_DIRECTORY ${PANDA_ROOT}
|
||||
RESULT_VARIABLE THIRD_PARTY_OK)
|
||||
if (NOT THIRD_PARTY_OK EQUAL 0)
|
||||
message(FATAL_ERROR "Unable to install required third-party dependencies")
|
||||
endif()
|
||||
|
||||
if(PANDA_WITH_TOOLCHAIN)
|
||||
add_subdirectory(isa)
|
||||
|
||||
set(SECUREC_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/securec)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/securec)
|
||||
add_subdirectory(libpandabase)
|
||||
|
||||
set(MINIZ_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/miniz/amalgamation)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/miniz)
|
||||
add_subdirectory(libziparchive)
|
||||
|
||||
add_subdirectory(libpandafile)
|
||||
if(NOT PANDA_TARGET_WINDOWS)
|
||||
add_subdirectory(libpandafile/external)
|
||||
endif()
|
||||
|
||||
add_subdirectory(assembler)
|
||||
add_subdirectory(disassembler)
|
||||
|
||||
if(PANDA_WITH_RUNTIME)
|
||||
if (PANDA_TARGET_X86 OR PANDA_TARGET_AMD64)
|
||||
add_subdirectory(verification/tests)
|
||||
endif()
|
||||
add_subdirectory(verification/gen)
|
||||
add_subdirectory(verification)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PANDA_WITH_RUNTIME)
|
||||
add_subdirectory(pandastdlib)
|
||||
|
||||
if(NOT PANDA_TARGET_WINDOWS)
|
||||
add_subdirectory(dprof)
|
||||
endif()
|
||||
|
||||
add_subdirectory(runtime)
|
||||
|
||||
add_subdirectory(panda)
|
||||
|
||||
add_subdirectory(verification/verifier)
|
||||
|
||||
endif()
|
||||
|
||||
# ----- Testing ----------------------------------------------------------------
|
||||
|
||||
if(PANDA_WITH_TESTS)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/googletest)
|
||||
target_compile_options(gtest PUBLIC "-Wno-shadow" "-Wno-pedantic")
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
||||
add_custom_target(tests_full COMMENT "Running all test suites and code checks")
|
||||
add_dependencies(tests_full
|
||||
check_concurrency_format
|
||||
tests
|
||||
)
|
||||
if(NOT PANDA_TARGET_MACOS)
|
||||
add_dependencies(tests_full clang_format)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ----- Benchmarking -----------------------------------------------------------
|
||||
|
||||
if(PANDA_WITH_BENCHMARKS)
|
||||
# NB! Please do not merge benchmarks and tests unless you want to mess with
|
||||
# slow builds, etc. If you want some coupling, you might want to make benchmarks
|
||||
# depend on tests some day.
|
||||
|
||||
add_custom_target(benchmarks COMMENT "Running all benchmark suites")
|
||||
add_subdirectory(tests/benchmarks)
|
||||
endif()
|
||||
|
||||
# ----- Aliases ----------------------------------------------------------------
|
||||
|
||||
add_custom_target(panda_bins COMMENT "Build all common Panda binaries")
|
||||
add_dependencies(panda_bins panda pandasm)
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<!-- OAT(OSS Audit Tool) configuration guide:
|
||||
basedir: Root dir, the basedir + project path is the real source file location.
|
||||
licensefile:
|
||||
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
|
||||
|
||||
tasklist(only for batch mode):
|
||||
1. task: Define oat check thread, each task will start a new thread.
|
||||
2. task name: Only an name, no practical effect.
|
||||
3. task policy: Default policy for projects under this task, this field is required and the specified policy must defined in policylist.
|
||||
4. task filter: Default filefilter for projects under this task, this field is required and the specified filefilter must defined in filefilterlist.
|
||||
5. task project: Projects to be checked, the path field define the source root dir of the project.
|
||||
|
||||
|
||||
policyList:
|
||||
1. policy: All policyitems will be merged to default OAT.xml rules, the name of policy doesn't affect OAT check process.
|
||||
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
|
||||
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
3. policyitem type:
|
||||
"compatibility" is used to check license compatibility in the specified path;
|
||||
"license" is used to check source license header in the specified path;
|
||||
"copyright" is used to check source copyright header in the specified path;
|
||||
"import" is used to check source dependency in the specified path, such as import ... ,include ...
|
||||
"filetype" is used to check file type in the specified path, supported file types: archive, binary
|
||||
"filename" is used to check whether the specified file exists in the specified path(support projectroot in default OAT.xml), supported file names: LICENSE, README, README.OpenSource
|
||||
|
||||
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
|
||||
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
|
||||
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
|
||||
7. policyitem filefilter: Used to bind filefilter which define filter rules.
|
||||
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
|
||||
|
||||
Note:If the text contains special characters, please escape them according to the following rules:
|
||||
" == >
|
||||
& == >
|
||||
' == >
|
||||
< == >
|
||||
> == >
|
||||
-->
|
||||
<configuration>
|
||||
<oatconfig>
|
||||
<policy name="defaultPolicy" desc="" >
|
||||
<policyitem type="compatibility" name="Apache" path="ark/runtime_core" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter" desc=""/>
|
||||
</policy>
|
||||
<filefilterlist>
|
||||
<filefilter name="binaryFileTypePolicyFilter" desc="二进制文件校验策略的过滤条件" >
|
||||
</filefilter>
|
||||
<filefilter name="copyrightPolicyFilter" desc="copyright文件头校验策略的过滤条件" >
|
||||
</filefilter>
|
||||
<filefilter name="defaultPolicyFilter" desc="根目录LICENSE文件校验策略的过滤条件xxx" >
|
||||
</filefilter>
|
||||
</filefilterlist>
|
||||
</oatconfig>
|
||||
</configuration>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# ark_runtime_core
|
||||
|
||||
#### Description
|
||||
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
|
||||
|
||||
#### Software Architecture
|
||||
Software architecture description
|
||||
|
||||
#### Installation
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Instructions
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Contribution
|
||||
|
||||
1. Fork the repository
|
||||
2. Create Feat_xxx branch
|
||||
3. Commit your code
|
||||
4. Create Pull Request
|
||||
|
||||
|
||||
#### Gitee Feature
|
||||
|
||||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
@@ -1,39 +1,148 @@
|
||||
# ark_runtime_core
|
||||
# Runtime<a name="EN-US_TOPIC_0000001138850082"></a>
|
||||
|
||||
#### 介绍
|
||||
{**以下是 Gitee 平台说明,您可以替换此简介**
|
||||
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
|
||||
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
|
||||
- [Introduction](#section11660541593)
|
||||
- [Directory Structure](#section161941989596)
|
||||
- [Usage Guidelines](#section1312121216216)
|
||||
- [Repositories Involved](#section1371113476307)
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
## Introduction<a name="section11660541593"></a>
|
||||
|
||||
As a common module of ARK runtime, Runtime consists of some basic language-irrelevant runtime libraries, including ARK File, Tooling, and ARK Base. ARK File provides bytecodes and information required for executing bytecodes. Tooling supports Debugger. ARK Base is responsible for implementing system calls.
|
||||
|
||||
#### 安装教程
|
||||
## Directory Structure<a name="section161941989596"></a>
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
```
|
||||
/ark/runtime_core
|
||||
├── assembler # Assembler that converts an ARK bytecode file (*.pa) in text format into a bytecode file (*.abc) in binary format. For details about the format, see docs/assembly_format.md and docs/file_format.md.
|
||||
├── cmake # cmake script that contains the toolchain files and common cmake functions used to define the build and test targets.
|
||||
├── CMakeLists.txt # cmake main entry file.
|
||||
├── disassembler # Disassembler that converts an ARK bytecode file (*.abc) in binary format into an ARK bytecode file (*.pa) in text format.
|
||||
├── docs # Language frontend, ARK file format, and runtime design documents.
|
||||
├── dprof # Data used to collect the profiling data for ARK runtime.
|
||||
├── gn # GN templates and configuration files.
|
||||
├── isa # Bytecode ISA description file YAML, and Ruby scripts and templates.
|
||||
├── ldscripts # Linker scripts used to place ELF sections larger than 4 GB in a non-PIE executable file.
|
||||
├── libpandabase # Basic ARK runtime library, including logs, synchronization primitives, and common data structure.
|
||||
├── libpandafile # Source code repository of ARK bytecode files (*.abc) in binary format.
|
||||
├── libziparchive # provides APIs for reading and using zip files implemented by miniz.
|
||||
├── panda # CLI tool used to execute ARK bytecode files (*.abc).
|
||||
├── pandastdlib # Standard libraries wrote by the ARK assembler.
|
||||
├── resources # CI jobs description files.
|
||||
├── runtime # ARK runtime command module.
|
||||
├── scripts # CI scripts.
|
||||
├── templates # Ruby templates and scripts used to process command line options, loggers, error messages, and events.
|
||||
├── tests # UT test cases.
|
||||
└── verification # Bytecode verifier. See docs/bc_verification.
|
||||
|
||||
#### 使用说明
|
||||
```
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
## Usage Guidelines<a name="section1312121216216"></a>
|
||||
|
||||
#### 参与贡献
|
||||
Assembler ark\_asm
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
The ark\_asm assembler converts a text ARK bytecode file into a bytecode file in binary format.
|
||||
|
||||
Command:
|
||||
|
||||
#### 特技
|
||||
```
|
||||
ark_asm [Option] Input file Output file
|
||||
```
|
||||
|
||||
<a name="table11141827153017"></a>
|
||||
<table><thead align="left"><tr id="row101462717303"><th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.1"><p id="p51552743010"><a name="p51552743010"></a><a name="p51552743010"></a>Option</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.2"><p id="p11592710304"><a name="p11592710304"></a><a name="p11592710304"></a>Description</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row2015172763014"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p171592710306"><a name="p171592710306"></a><a name="p171592710306"></a>--dump-scopes</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p13151527133011"><a name="p13151527133011"></a><a name="p13151527133011"></a>Saves the result to a JSON file to support the debug mode in Visual Studio Code.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1015527173015"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p1615182712308"><a name="p1615182712308"></a><a name="p1615182712308"></a>--help</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p9556101593120"><a name="p9556101593120"></a><a name="p9556101593120"></a>Displays help information.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1015112763020"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p1815182733012"><a name="p1815182733012"></a><a name="p1815182733012"></a>--log-file</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1615627173019"><a name="p1615627173019"></a><a name="p1615627173019"></a>Specifies the log file output path after log printing is enabled.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row131515277307"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p111572716304"><a name="p111572716304"></a><a name="p111572716304"></a>--optimize</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p25842312319"><a name="p25842312319"></a><a name="p25842312319"></a>Enables compilation optimization.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1815112753020"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p2151927193015"><a name="p2151927193015"></a><a name="p2151927193015"></a>--size-stat</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1715312588115"><a name="p1715312588115"></a><a name="p1715312588115"></a>Collects statistics on and prints ARK bytecode information after conversion.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1915182703012"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p17151527133017"><a name="p17151527133017"></a><a name="p17151527133017"></a>--verbose</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p15761152983113"><a name="p15761152983113"></a><a name="p15761152983113"></a>Enables log printing.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Input file: ARK bytecodes in text format
|
||||
|
||||
Output file: ARK bytecodes in binary format
|
||||
|
||||
Disassembler ark\_dissam
|
||||
|
||||
The ark\_dissam disassembler converts a bytecode file in binary format into a text ARK bytecode file.
|
||||
|
||||
Command:
|
||||
|
||||
```
|
||||
ark_dissam [Option] Input file Output file
|
||||
```
|
||||
|
||||
<a name="table125062517328"></a>
|
||||
<table><thead align="left"><tr id="row125182553217"><th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.1"><p id="p175162514327"><a name="p175162514327"></a><a name="p175162514327"></a>Option</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.2"><p id="p6512255324"><a name="p6512255324"></a><a name="p6512255324"></a>Description</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row5511825103218"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p45172513326"><a name="p45172513326"></a><a name="p45172513326"></a>--debug</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1245695053215"><a name="p1245695053215"></a><a name="p1245695053215"></a>Enables the function for printing debug information.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row951112515321"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p451192515323"><a name="p451192515323"></a><a name="p451192515323"></a>--debug-file</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p175142583210"><a name="p175142583210"></a><a name="p175142583210"></a>Specifies the path of the debug information output file. The default value is <strong id="b1486165094613"><a name="b1486165094613"></a><a name="b1486165094613"></a>std::cout</strong>.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row45116253325"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p85116259328"><a name="p85116259328"></a><a name="p85116259328"></a>--help</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1348135833214"><a name="p1348135833214"></a><a name="p1348135833214"></a>Displays help information.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row194197407327"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p154205401325"><a name="p154205401325"></a><a name="p154205401325"></a>--verbose</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p369871173312"><a name="p369871173312"></a><a name="p369871173312"></a>Outputs the comments of the output file.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Input file: ARK bytecodes in binary format
|
||||
|
||||
Output file: ARK bytecodes in text format
|
||||
|
||||
## Repositories Involved<a name="section1371113476307"></a>
|
||||
|
||||
[ARK Runtime Subsystem](https://gitee.com/wanyanglan/ark_js_runtime/blob/master/docs/ARK-Runtime-Subsystem.md)
|
||||
|
||||
**[ark/runtime\_core](README_zh.md)**
|
||||
|
||||
[ark/js\_runtime](https://gitee.com/openharmony/ark_js_runtime/blob/master/README.md)
|
||||
|
||||
[ark/ts2abc](https://gitee.com/openharmony/ark_js_runtime/blob/master/README.md)
|
||||
|
||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
|
||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
# 方舟公共组件<a name="ZH-CN_TOPIC_0000001138850082"></a>
|
||||
|
||||
- [简介](#section11660541593)
|
||||
- [目录](#section161941989596)
|
||||
- [使用说明](#section1312121216216)
|
||||
- [相关仓](#section1371113476307)
|
||||
|
||||
## 简介<a name="section11660541593"></a>
|
||||
|
||||
Runtime组件是方舟运行时的公共组件,主要包括一些语言无关的基础运行库,包含承载字节码以及执行字节码所需要相关信息的ARK File、支持Debugger的Tooling、负责对应系统调用的ARK Base等。
|
||||
|
||||
## 目录<a name="section161941989596"></a>
|
||||
|
||||
```
|
||||
/ark/runtime_core
|
||||
├── assembler # 汇编器,将文本格式的方舟字节码文件(*.pa)转换为二进制格式的字节码文件(*.abc),具体格式见:docs/assembly_format.md和docs/file_format.md
|
||||
├── cmake # cmake脚本,包含工具链文件和用于定义构建和测试目标的常用cmake函数
|
||||
├── CMakeLists.txt # cmake主入口文件
|
||||
├── disassembler # 反汇编器,将二进制格式的方舟字节码文件(*.abc)转换为文本格式的方舟字节码文件(*.pa)
|
||||
├── docs # 包含语言前端、方舟文件格式和运行时的设计文档。
|
||||
├── dprof # 用于ARK运行时搜集profile数据
|
||||
├── gn # GN模板和配置文件
|
||||
├── isa # 字节码ISA描述文件YAML,和ruby脚本和模板
|
||||
├── ldscripts # 包含链接器脚本,用于在非PIE可执行文件中放置4GB以上的ELF section。
|
||||
├── libpandabase # ARK运行时基本库,包含:日志、同步原语、公共数据结构等
|
||||
├── libpandafile # 二进制格式的方舟字节码文件(*.abc)源码仓
|
||||
├── libziparchive # 提供读取和使用miniz的ZIP压缩文件的API。
|
||||
├── panda # CLI工具,用于执行方舟字节码文件(*.abc)文件
|
||||
├── pandastdlib # 通过方舟汇编编写的标准库
|
||||
├── resources # CI jobs描述文件
|
||||
├── runtime # ARK运行时公共组件
|
||||
├── scripts # CI脚本
|
||||
├── templates # ruby模板和脚本,处理包括:命令行选项、记录器组件、错误消息、事件等
|
||||
├── tests # UT用例
|
||||
└── verification # 字节码验证器,具体可以参考 docs/bc_verification
|
||||
|
||||
```
|
||||
|
||||
## 使用说明<a name="section1312121216216"></a>
|
||||
|
||||
汇编器工具概述
|
||||
|
||||
工具名称为ark\_asm,用于将文本格式的方舟字节码文件转换为二进制格式的方舟字节码文件。
|
||||
|
||||
命令行格式:
|
||||
|
||||
```
|
||||
ark_asm [选项] 输入文件 输出文件
|
||||
```
|
||||
|
||||
<a name="table11141827153017"></a>
|
||||
<table><thead align="left"><tr id="row101462717303"><th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.1"><p id="p51552743010"><a name="p51552743010"></a><a name="p51552743010"></a>选项</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.2"><p id="p11592710304"><a name="p11592710304"></a><a name="p11592710304"></a>描述</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row2015172763014"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p171592710306"><a name="p171592710306"></a><a name="p171592710306"></a>--dump-scopes</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p13151527133011"><a name="p13151527133011"></a><a name="p13151527133011"></a>将结果保存到json文件中,以支持在VS Code中的debug模式</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1015527173015"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p1615182712308"><a name="p1615182712308"></a><a name="p1615182712308"></a>--help</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p9556101593120"><a name="p9556101593120"></a><a name="p9556101593120"></a>帮助提示</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1015112763020"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p1815182733012"><a name="p1815182733012"></a><a name="p1815182733012"></a>--log-file</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1615627173019"><a name="p1615627173019"></a><a name="p1615627173019"></a>使能log打印后,指定log文件输出路径</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1815112753020"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p2151927193015"><a name="p2151927193015"></a><a name="p2151927193015"></a>--size-stat</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1715312588115"><a name="p1715312588115"></a><a name="p1715312588115"></a>统计并打印出转换后方舟字节码信息</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1915182703012"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p17151527133017"><a name="p17151527133017"></a><a name="p17151527133017"></a>--verbose</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p15761152983113"><a name="p15761152983113"></a><a name="p15761152983113"></a>使能log打印</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
输入文件:文本格式的方舟字节码
|
||||
|
||||
输出文件:二进制格式的方舟字节码
|
||||
|
||||
反汇编器工具概述
|
||||
|
||||
工具名称为ark\_dissam,用于将二进制格式的方舟字节码文件转换为可读的文本格式的方舟字节码文件。
|
||||
|
||||
命令行格式:
|
||||
|
||||
```
|
||||
ark_dissam [选项] 输入文件 输出文件
|
||||
```
|
||||
|
||||
<a name="table125062517328"></a>
|
||||
<table><thead align="left"><tr id="row125182553217"><th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.1"><p id="p175162514327"><a name="p175162514327"></a><a name="p175162514327"></a>选项</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="50%" id="mcps1.1.3.1.2"><p id="p6512255324"><a name="p6512255324"></a><a name="p6512255324"></a>描述</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row5511825103218"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p45172513326"><a name="p45172513326"></a><a name="p45172513326"></a>--debug</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1245695053215"><a name="p1245695053215"></a><a name="p1245695053215"></a>使能调试信息</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row951112515321"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p451192515323"><a name="p451192515323"></a><a name="p451192515323"></a>--debug-file</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p175142583210"><a name="p175142583210"></a><a name="p175142583210"></a>调试信息输出文件路径,默认为std::cout</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row45116253325"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p85116259328"><a name="p85116259328"></a><a name="p85116259328"></a>--help</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p1348135833214"><a name="p1348135833214"></a><a name="p1348135833214"></a>帮助提示</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row194197407327"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.1 "><p id="p154205401325"><a name="p154205401325"></a><a name="p154205401325"></a>--verbose</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.1.3.1.2 "><p id="p369871173312"><a name="p369871173312"></a><a name="p369871173312"></a>增加输出汇编文件的注释信息</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
输入文件:二进制格式的方舟字节码
|
||||
|
||||
输出文件:文本格式的方舟字节码
|
||||
|
||||
## 相关仓<a name="section1371113476307"></a>
|
||||
|
||||
[方舟运行时子系统](https://gitee.com/wanyanglan/ark_js_runtime/blob/master/docs/%E6%96%B9%E8%88%9F%E8%BF%90%E8%A1%8C%E6%97%B6%E5%AD%90%E7%B3%BB%E7%BB%9F.md)
|
||||
|
||||
**[ark/runtime\_core](README_zh.md)**
|
||||
|
||||
[ark/js\_runtime](https://gitee.com/openharmony/ark_js_runtime/blob/master/README_zh.md)
|
||||
|
||||
[ark/ts2abc](https://gitee.com/openharmony/ark_ts2abc/blob/master/README_zh.md)
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
# 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.
|
||||
|
||||
if (!defined(ark_standalone_build)) {
|
||||
ark_standalone_build = false
|
||||
}
|
||||
|
||||
if (ark_standalone_build) {
|
||||
ark_root = "//"
|
||||
ark_third_party_root = "//ark-third-party"
|
||||
with_ecmascript = true
|
||||
use_pbqp = true
|
||||
} else {
|
||||
ark_root = "//ark/runtime_core"
|
||||
ark_third_party_root = "//third_party"
|
||||
with_ecmascript = false
|
||||
use_pbqp = false
|
||||
}
|
||||
|
||||
ark_enable_global_register_variables = true
|
||||
enable_bytecode_optimizer = false
|
||||
|
||||
if (ark_standalone_build) {
|
||||
sdk_libc_secshared_dep = "$ark_third_party_root/securec:libc_secshared"
|
||||
sdk_libc_secshared_config =
|
||||
"$ark_third_party_root/securec:libsec_public_config"
|
||||
|
||||
if (is_mingw || is_mac || is_linux) {
|
||||
sdk_libc_secshared_dep = "$ark_third_party_root/securec:libc_secstatic"
|
||||
}
|
||||
} else {
|
||||
sdk_libc_secshared_dep = "//utils/native/base:utilsecurec_shared"
|
||||
sdk_libc_secshared_config = "//utils/native/base:utils_config"
|
||||
|
||||
if (is_mingw || is_mac || is_linux) {
|
||||
sdk_libc_secshared_dep = "//utils/native/base:utilsecurec"
|
||||
}
|
||||
}
|
||||
|
||||
# Generate file for a template and YAML data provided.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# data_file -- YAML data full name
|
||||
# template_file -- template full name
|
||||
# output_file -- output file full name
|
||||
# requires -- a list of scripts that provide data-querying API for templates
|
||||
# extra_dependencies -- a list of files that should be considered as dependencies, must be lable
|
||||
template("ark_gen_file") {
|
||||
assert(defined(invoker.data_file), "data_file is required!")
|
||||
assert(defined(invoker.template_file), "template_file is required!")
|
||||
assert(defined(invoker.output_file), "output_file is required!")
|
||||
|
||||
requires = ""
|
||||
if (defined(invoker.requires)) {
|
||||
requires = string_join(",", rebase_path(invoker.requires, root_build_dir))
|
||||
}
|
||||
|
||||
extra_dependencies = []
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
extra_dependencies += invoker.extra_dependencies
|
||||
}
|
||||
|
||||
action("$target_name") {
|
||||
script = "$ark_root/isa/gen.rb"
|
||||
|
||||
# rerun action when data file or template file update
|
||||
inputs = [
|
||||
invoker.template_file,
|
||||
invoker.data_file,
|
||||
]
|
||||
outputs = [ invoker.output_file ]
|
||||
args = [
|
||||
"--template",
|
||||
rebase_path(invoker.template_file, root_build_dir),
|
||||
"--data",
|
||||
rebase_path(invoker.data_file, root_build_dir),
|
||||
"--require",
|
||||
requires,
|
||||
"--output",
|
||||
rebase_path(outputs[0]),
|
||||
]
|
||||
|
||||
deps = extra_dependencies
|
||||
}
|
||||
}
|
||||
|
||||
# Generate files based on templates and YAML data provided.
|
||||
# Adds targets for every template. Also adds a target for the whole function invocation
|
||||
# with name ${data_name}_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# * data -- data source, YAML file
|
||||
# * template_files -- a list of templates to generate files
|
||||
# * requires -- a list of Ruby scripts that provide data-querying API for templates
|
||||
#
|
||||
# Optional arguments:
|
||||
# * sources -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates
|
||||
# * destination -- a directory for output files, default is ${PANDA_BINARY_ROOT}
|
||||
# * extra_dependencies -- a list of files that should be considered as dependencies
|
||||
template("ark_gen") {
|
||||
assert(defined(invoker.data), "data were not passed to ark_gen")
|
||||
assert(defined(invoker.template_files),
|
||||
"template_files were not passed to ark_gen")
|
||||
|
||||
dir = ""
|
||||
if (defined(invoker.sources)) {
|
||||
dir = invoker.sources
|
||||
} else {
|
||||
dir = "templates"
|
||||
}
|
||||
|
||||
destination = ""
|
||||
if (defined(invoker.destination)) {
|
||||
destination = invoker.destination
|
||||
} else {
|
||||
destination = target_out_dir
|
||||
}
|
||||
|
||||
input_requires = ""
|
||||
if (defined(invoker.requires)) {
|
||||
input_requires = invoker.requires
|
||||
}
|
||||
|
||||
foreach(t, invoker.template_files) {
|
||||
name = string_replace(t, ".erb", "")
|
||||
output = "${destination}/${name}"
|
||||
name = string_replace(name, ".", "_")
|
||||
name = string_replace(name, "/", "_")
|
||||
target = "${target_name}_${name}"
|
||||
|
||||
ark_gen_file(target) {
|
||||
data_file = invoker.data
|
||||
template_file = "${dir}/${t}"
|
||||
output_file = output
|
||||
requires = input_requires
|
||||
extra_dependencies = []
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
extra_dependencies += invoker.extra_dependencies
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Calls `ark_gen` for ISA YAML.
|
||||
# Adds targets for every template. Also adds a target for the whole function invocation
|
||||
# with name isa_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# * template_files -- a list of templates to generate files
|
||||
#
|
||||
# Optional arguments:
|
||||
# * sources -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates
|
||||
# * destination -- a directory for output files, default is ${target_out_dir}
|
||||
# * requires -- if defined, will require additional Ruby files for template generation, must be list
|
||||
# * extra_dependencies -- a list of files that should be considered as dependencies lable, must be list, not used
|
||||
template("ark_isa_gen") {
|
||||
isa_data = "$ark_root/isa/isa.yaml"
|
||||
isa_requires = [ "$ark_root/isa/isapi.rb" ]
|
||||
if (defined(invoker.requires)) {
|
||||
isa_requires += invoker.requires
|
||||
}
|
||||
|
||||
dependencies = []
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
dependencies += invoker.extra_dependencies
|
||||
}
|
||||
|
||||
ark_gen("$target_name") {
|
||||
data = isa_data
|
||||
template_files = invoker.template_files
|
||||
sources = invoker.sources
|
||||
destination = invoker.destination
|
||||
requires = isa_requires
|
||||
extra_dependencies = dependencies
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
# 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/runtime_core/ark_config.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
config("arkassembler_public_config") {
|
||||
include_dirs = [
|
||||
"$ark_root/assembler",
|
||||
"$target_gen_dir",
|
||||
"$target_gen_dir/include",
|
||||
]
|
||||
}
|
||||
|
||||
libarkassembler_sources = [
|
||||
"$target_gen_dir/builtin_parsing.cpp",
|
||||
"$target_gen_dir/ins_to_string.cpp",
|
||||
"annotation.cpp",
|
||||
"assembly-emitter.cpp",
|
||||
"assembly-parser.cpp",
|
||||
"assembly-program.cpp",
|
||||
"assembly-type.cpp",
|
||||
"assembly-ins.cpp",
|
||||
"context.cpp",
|
||||
"extensions/ecmascript/ecmascript_meta.cpp",
|
||||
"extensions/extensions.cpp",
|
||||
"lexer.cpp",
|
||||
"meta.cpp",
|
||||
]
|
||||
|
||||
libarkassembler_configs = [
|
||||
sdk_libc_secshared_config,
|
||||
"$ark_root:ark_config",
|
||||
":arkassembler_public_config",
|
||||
"$ark_root/libpandabase:arkbase_public_config",
|
||||
"$ark_root/libpandafile:arkfile_public_config",
|
||||
]
|
||||
|
||||
ohos_shared_library("libarkassembler") {
|
||||
sources = libarkassembler_sources
|
||||
|
||||
configs = libarkassembler_configs
|
||||
|
||||
deps = [
|
||||
":ark_asm_ecmascript_meta_gen_h",
|
||||
":ark_asm_ins_create_builtins_api_h",
|
||||
":ark_asm_meta_gen_h",
|
||||
":builtin_parsing_cpp",
|
||||
":isa_gen_libarkassembler_ins_create_api_h",
|
||||
":isa_gen_libarkassembler_ins_emit_h",
|
||||
":isa_gen_libarkassembler_ins_to_string_cpp",
|
||||
":isa_gen_libarkassembler_isa_h",
|
||||
":isa_gen_libarkassembler_opcode_parsing_h",
|
||||
":isa_gen_libarkassembler_operand_types_print_h",
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"$ark_root/libpandafile:libarkfile",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
if (!is_standard_system) {
|
||||
relative_install_dir = "ark"
|
||||
}
|
||||
output_extension = "so"
|
||||
subsystem_name = "ark"
|
||||
}
|
||||
|
||||
ohos_static_library("libarkassembler_frontend_static") {
|
||||
sources = libarkassembler_sources
|
||||
|
||||
configs = libarkassembler_configs
|
||||
|
||||
deps = [
|
||||
":ark_asm_ecmascript_meta_gen_h",
|
||||
":ark_asm_ins_create_builtins_api_h",
|
||||
":ark_asm_meta_gen_h",
|
||||
":builtin_parsing_cpp",
|
||||
":isa_gen_libarkassembler_ins_create_api_h",
|
||||
":isa_gen_libarkassembler_ins_emit_h",
|
||||
":isa_gen_libarkassembler_ins_to_string_cpp",
|
||||
":isa_gen_libarkassembler_isa_h",
|
||||
":isa_gen_libarkassembler_opcode_parsing_h",
|
||||
":isa_gen_libarkassembler_operand_types_print_h",
|
||||
"$ark_root/libpandabase:libarkbase_frontend_static",
|
||||
"$ark_root/libpandafile:libarkfile_frontend_static",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
}
|
||||
|
||||
ohos_executable("ark_asm") {
|
||||
sources = [ "pandasm.cpp" ]
|
||||
|
||||
include_dirs = [ "$target_gen_dir" ]
|
||||
|
||||
configs = [
|
||||
sdk_libc_secshared_config,
|
||||
":arkassembler_public_config",
|
||||
"$ark_root:ark_config",
|
||||
"$ark_root/libpandabase:arkbase_public_config",
|
||||
"$ark_root/libpandafile:arkfile_public_config",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":libarkassembler_frontend_static",
|
||||
"$ark_root/libpandabase:libarkbase_frontend_static",
|
||||
"$ark_root/libpandafile:libarkfile_frontend_static",
|
||||
]
|
||||
|
||||
if (!is_mingw && !ark_standalone_build) {
|
||||
ldflags = [ "-static-libstdc++" ]
|
||||
}
|
||||
|
||||
install_enable = true
|
||||
subsystem_name = "ark"
|
||||
}
|
||||
|
||||
ark_isa_gen("isa_gen_libarkassembler") {
|
||||
template_files = [
|
||||
"isa.h.erb",
|
||||
"ins_emit.h.erb",
|
||||
"ins_to_string.cpp.erb",
|
||||
"ins_create_api.h.erb",
|
||||
"opcode_parsing.h.erb",
|
||||
"operand_types_print.h.erb",
|
||||
]
|
||||
sources = "templates"
|
||||
destination = "$target_gen_dir"
|
||||
requires = [
|
||||
"asm_isapi.rb",
|
||||
"../libpandafile/pandafile_isapi.rb",
|
||||
]
|
||||
extra_dependencies = [
|
||||
":ark_asm_ins_create_builtins_api_h",
|
||||
":builtin_parsing_cpp",
|
||||
":builtin_parsing_tests_cpp",
|
||||
]
|
||||
}
|
||||
|
||||
ark_gen_file("ark_asm_meta_gen_h") {
|
||||
template_file = "templates/meta_gen.cpp.erb"
|
||||
data_file = "metadata.yaml"
|
||||
requires = [ "asm_metadata.rb" ]
|
||||
output_file = "$target_gen_dir/meta_gen.h"
|
||||
}
|
||||
|
||||
ark_gen_file("ark_asm_ins_create_builtins_api_h") {
|
||||
template_file = "templates/ins_create_builtins_api.h.erb"
|
||||
data_file = "../isa/builtins.yaml"
|
||||
requires = [ "../isa/builtinsapi.rb" ]
|
||||
output_file = "$target_gen_dir/ins_create_builtins_api.h"
|
||||
}
|
||||
|
||||
ark_gen_file("builtin_parsing_cpp") {
|
||||
template_file = "templates/builtin_parsing.cpp.erb"
|
||||
data_file = "../isa/builtins.yaml"
|
||||
requires = [
|
||||
"../isa/builtinsapi.rb",
|
||||
"//ark/js_runtime/ecmascript/ecma_builtins.rb"
|
||||
]
|
||||
output_file = "$target_gen_dir/builtin_parsing.cpp"
|
||||
}
|
||||
|
||||
ark_gen_file("builtin_parsing_tests_cpp") {
|
||||
template_file = "templates/builtin_parsing_tests.cpp.erb"
|
||||
data_file = "../isa/builtins.yaml"
|
||||
requires = [
|
||||
"../isa/builtinsapi.rb" ,
|
||||
"//ark/js_runtime/ecmascript/ecma_builtins.rb"
|
||||
]
|
||||
output_file = "$target_gen_dir/builtin_parsing_tests.cpp"
|
||||
}
|
||||
|
||||
ark_gen_file("ark_asm_ecmascript_meta_gen_h") {
|
||||
template_file = "templates/meta_gen.cpp.erb"
|
||||
data_file = "extensions/ecmascript/metadata.yaml"
|
||||
requires = [ "asm_metadata.rb" ]
|
||||
output_file = "$target_gen_dir/ecmascript_meta_gen.h"
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.3.2 FATAL_ERROR)
|
||||
project(assembler CXX)
|
||||
|
||||
panda_add_executable(ark_asm pandasm.cpp)
|
||||
|
||||
set(INS_CREATE_BUILTINS_API_H ${CMAKE_CURRENT_BINARY_DIR}/ins_create_builtins_api.h)
|
||||
panda_gen_file(
|
||||
DATAFILE ${PANDA_ROOT}/isa/builtins.yaml
|
||||
TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/ins_create_builtins_api.h.erb
|
||||
REQUIRES ${PANDA_ROOT}/isa/builtinsapi.rb
|
||||
OUTPUTFILE ${INS_CREATE_BUILTINS_API_H}
|
||||
)
|
||||
|
||||
set(BUILTIN_PARSING_CPP ${CMAKE_CURRENT_BINARY_DIR}/builtin_parsing.cpp)
|
||||
panda_gen_file(
|
||||
DATAFILE ${PANDA_ROOT}/isa/builtins.yaml
|
||||
TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/builtin_parsing.cpp.erb
|
||||
REQUIRES ${PANDA_ROOT}/isa/builtinsapi.rb
|
||||
OUTPUTFILE ${BUILTIN_PARSING_CPP}
|
||||
)
|
||||
|
||||
set(PANDASM_BIN_TESTS ${CMAKE_CURRENT_BINARY_DIR}/tests)
|
||||
file(MAKE_DIRECTORY "${PANDASM_BIN_TESTS}")
|
||||
|
||||
set(BUILTIN_PARSING_TESTS_CPP ${PANDASM_BIN_TESTS}/builtin_parsing_tests.cpp)
|
||||
panda_gen_file(
|
||||
DATAFILE ${PANDA_ROOT}/isa/builtins.yaml
|
||||
TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/builtin_parsing_tests.cpp.erb
|
||||
REQUIRES ${PANDA_ROOT}/isa/builtinsapi.rb
|
||||
OUTPUTFILE ${BUILTIN_PARSING_TESTS_CPP}
|
||||
)
|
||||
|
||||
panda_isa_gen(
|
||||
TEMPLATES
|
||||
"isa.h.erb"
|
||||
"ins_emit.h.erb"
|
||||
"ins_to_string.cpp.erb"
|
||||
"ins_create_api.h.erb"
|
||||
"opcode_parsing.h.erb"
|
||||
"operand_types_print.h.erb"
|
||||
REQUIRES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/asm_isapi.rb"
|
||||
"${PANDA_ROOT}/libpandafile/pandafile_isapi.rb"
|
||||
EXTRA_DEPENDENCIES
|
||||
${INS_CREATE_BUILTINS_API_H}
|
||||
${BUILTIN_PARSING_CPP}
|
||||
${BUILTIN_PARSING_TESTS_CPP}
|
||||
)
|
||||
|
||||
add_library(arkassembler ${PANDA_DEFAULT_LIB_TYPE}
|
||||
lexer.cpp
|
||||
annotation.cpp
|
||||
assembly-emitter.cpp
|
||||
assembly-parser.cpp
|
||||
assembly-program.cpp
|
||||
assembly-type.cpp
|
||||
assembly-ins.cpp
|
||||
context.cpp
|
||||
meta.cpp
|
||||
ins_to_string.cpp
|
||||
extensions/extensions.cpp
|
||||
extensions/ecmascript/ecmascript_meta.cpp
|
||||
builtin_parsing.cpp
|
||||
)
|
||||
|
||||
add_dependencies(arkassembler isa_gen_assembler arkfile)
|
||||
|
||||
set(META_GEN_H ${CMAKE_CURRENT_BINARY_DIR}/meta_gen.h)
|
||||
panda_gen_file(
|
||||
DATAFILE ${CMAKE_CURRENT_SOURCE_DIR}/metadata.yaml
|
||||
TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/meta_gen.cpp.erb
|
||||
OUTPUTFILE ${META_GEN_H}
|
||||
REQUIRES ${CMAKE_CURRENT_SOURCE_DIR}/asm_metadata.rb
|
||||
)
|
||||
|
||||
set(ECMASCRIPT_META_GEN_H ${CMAKE_CURRENT_BINARY_DIR}/ecmascript_meta_gen.h)
|
||||
panda_gen_file(
|
||||
DATAFILE ${CMAKE_CURRENT_SOURCE_DIR}/extensions/ecmascript/metadata.yaml
|
||||
TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/meta_gen.cpp.erb
|
||||
OUTPUTFILE ${ECMASCRIPT_META_GEN_H}
|
||||
REQUIRES ${CMAKE_CURRENT_SOURCE_DIR}/asm_metadata.rb
|
||||
)
|
||||
|
||||
add_custom_target(meta_gen_assembler DEPENDS ${META_GEN_H} ${ECMASCRIPT_META_GEN_H})
|
||||
|
||||
add_dependencies(arkassembler meta_gen_assembler)
|
||||
|
||||
target_include_directories(arkassembler
|
||||
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
panda_add_to_clang_tidy(TARGET ark_asm CHECKS
|
||||
"-cert-dcl21-cpp"
|
||||
"-cppcoreguidelines-macro-usage"
|
||||
"-google-runtime-references"
|
||||
"-misc-non-private-member-variables-in-classes"
|
||||
)
|
||||
|
||||
target_link_libraries(arkassembler arkfile)
|
||||
target_link_libraries(ark_asm arkassembler arkbase)
|
||||
|
||||
include_directories(${PANDA_ROOT}/libpandabase/)
|
||||
|
||||
panda_add_gtest(
|
||||
NAME assembler_tests
|
||||
SOURCES
|
||||
tests/lexer_test.cpp
|
||||
tests/parser_test.cpp
|
||||
tests/emitter_test.cpp
|
||||
tests/mangling_tests.cpp
|
||||
${PANDASM_BIN_TESTS}/builtin_parsing_tests.cpp
|
||||
LIBRARIES
|
||||
arkbase arkassembler
|
||||
SANITIZERS
|
||||
${PANDA_SANITIZERS_LIST}
|
||||
)
|
||||
if(TARGET assembler_tests)
|
||||
target_compile_options(assembler_tests PUBLIC "-Wno-ignored-attributes")
|
||||
endif()
|
||||
|
||||
panda_add_sanitizers(TARGET arkassembler SANITIZERS ${PANDA_SANITIZERS_LIST})
|
||||
panda_add_sanitizers(TARGET ark_asm SANITIZERS ${PANDA_SANITIZERS_LIST})
|
||||
|
||||
add_custom_target(pandasm ALL
|
||||
COMMAND cd $<TARGET_FILE_DIR:ark_asm> && ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE_NAME:ark_asm> pandasm)
|
||||
|
||||
add_dependencies(pandasm ark_asm)
|
||||
|
||||
if (PANDA_ENABLE_AFL)
|
||||
include("${PANDA_ROOT}/fuzzing/Fuzzing.cmake")
|
||||
panda_substitute_libs(TARGET arkassembler LIBS arkbase c_secshared arkfile)
|
||||
endif()
|
||||
|
||||
add_check_style(".")
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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 "annotation.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
||||
std::unique_ptr<ScalarValue> InitScalarValue(const ScalarValue &sc_val)
|
||||
{
|
||||
std::unique_ptr<ScalarValue> copy_val;
|
||||
switch (sc_val.GetType()) {
|
||||
case Value::Type::U1: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U1>(sc_val.GetValue<uint8_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U8: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U8>(sc_val.GetValue<uint8_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U16: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U16>(sc_val.GetValue<uint16_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U32: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U32>(sc_val.GetValue<uint32_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U64: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U64>(sc_val.GetValue<uint64_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I8: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I8>(sc_val.GetValue<int8_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I16: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I16>(sc_val.GetValue<int16_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I32: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I32>(sc_val.GetValue<int32_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I64: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I64>(sc_val.GetValue<int64_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::F32: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::F32>(sc_val.GetValue<float>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::F64: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::F64>(sc_val.GetValue<double>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::STRING: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::STRING>(sc_val.GetValue<std::string>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::STRING_NULLPTR: {
|
||||
copy_val = std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::STRING_NULLPTR>(sc_val.GetValue<int32_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::RECORD: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::RECORD>(sc_val.GetValue<Type>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::METHOD: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::METHOD>(sc_val.GetValue<std::string>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::ENUM: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::ENUM>(sc_val.GetValue<std::string>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::ANNOTATION: {
|
||||
copy_val = std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::ANNOTATION>(sc_val.GetValue<AnnotationData>()));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
copy_val = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return copy_val;
|
||||
}
|
||||
|
||||
std::unique_ptr<Value> making_value(const AnnotationElement &ann_elem)
|
||||
{
|
||||
std::unique_ptr<Value> copy_val;
|
||||
switch (ann_elem.GetValue()->GetType()) {
|
||||
case Value::Type::U1:
|
||||
case Value::Type::U8:
|
||||
case Value::Type::U16:
|
||||
case Value::Type::U32:
|
||||
case Value::Type::U64:
|
||||
case Value::Type::I8:
|
||||
case Value::Type::I16:
|
||||
case Value::Type::I32:
|
||||
case Value::Type::I64:
|
||||
case Value::Type::F32:
|
||||
case Value::Type::F64:
|
||||
case Value::Type::STRING:
|
||||
case Value::Type::STRING_NULLPTR:
|
||||
case Value::Type::RECORD:
|
||||
case Value::Type::METHOD:
|
||||
case Value::Type::ENUM:
|
||||
case Value::Type::ANNOTATION: {
|
||||
copy_val = InitScalarValue(*static_cast<ScalarValue *>(ann_elem.GetValue()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::ARRAY: {
|
||||
Value::Type c_type;
|
||||
auto *elem_arr = static_cast<ArrayValue *>(ann_elem.GetValue());
|
||||
if (elem_arr->GetValues().size() == 0) {
|
||||
c_type = Value::Type::VOID;
|
||||
} else {
|
||||
c_type = elem_arr->GetValues().front().GetType();
|
||||
}
|
||||
std::vector<ScalarValue> sc_vals;
|
||||
for (const auto &sc_val : elem_arr->GetValues()) {
|
||||
sc_vals.push_back(*InitScalarValue(sc_val));
|
||||
}
|
||||
copy_val = std::make_unique<ArrayValue>(c_type, std::move(sc_vals));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
copy_val = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return copy_val;
|
||||
}
|
||||
|
||||
AnnotationElement::AnnotationElement(const AnnotationElement &ann_elem)
|
||||
{
|
||||
this->value_ = making_value(ann_elem);
|
||||
this->name_ = ann_elem.GetName();
|
||||
}
|
||||
|
||||
AnnotationElement &AnnotationElement::operator=(const AnnotationElement &ann_elem)
|
||||
{
|
||||
if (this == &ann_elem) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
this->value_ = making_value(ann_elem);
|
||||
this->name_ = ann_elem.GetName();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScalarValue *Value::GetAsScalar()
|
||||
{
|
||||
ASSERT(!IsArray());
|
||||
return static_cast<ScalarValue *>(this);
|
||||
}
|
||||
|
||||
const ScalarValue *Value::GetAsScalar() const
|
||||
{
|
||||
ASSERT(!IsArray());
|
||||
return static_cast<const ScalarValue *>(this);
|
||||
}
|
||||
|
||||
ArrayValue *Value::GetAsArray()
|
||||
{
|
||||
ASSERT(IsArray());
|
||||
return static_cast<ArrayValue *>(this);
|
||||
}
|
||||
|
||||
const ArrayValue *Value::GetAsArray() const
|
||||
{
|
||||
ASSERT(IsArray());
|
||||
return static_cast<const ArrayValue *>(this);
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::string AnnotationElement::TypeToString(Value::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Value::Type::U1:
|
||||
return "u1";
|
||||
case Value::Type::I8:
|
||||
return "i8";
|
||||
case Value::Type::U8:
|
||||
return "u8";
|
||||
case Value::Type::I16:
|
||||
return "i16";
|
||||
case Value::Type::U16:
|
||||
return "u16";
|
||||
case Value::Type::I32:
|
||||
return "i32";
|
||||
case Value::Type::U32:
|
||||
return "u32";
|
||||
case Value::Type::I64:
|
||||
return "i64";
|
||||
case Value::Type::U64:
|
||||
return "u64";
|
||||
case Value::Type::F32:
|
||||
return "f32";
|
||||
case Value::Type::F64:
|
||||
return "f64";
|
||||
case Value::Type::STRING:
|
||||
return "string";
|
||||
case Value::Type::RECORD:
|
||||
return "class";
|
||||
case Value::Type::METHOD:
|
||||
return "method";
|
||||
case Value::Type::ENUM:
|
||||
return "enum";
|
||||
case Value::Type::ANNOTATION:
|
||||
return "annotation";
|
||||
case Value::Type::ARRAY:
|
||||
return "array";
|
||||
case Value::Type::VOID:
|
||||
return "void";
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ANNOTATION_H_
|
||||
#define PANDA_ASSEMBLER_ANNOTATION_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-type.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class AnnotationElement;
|
||||
|
||||
class AnnotationData {
|
||||
public:
|
||||
AnnotationData(std::string_view record_name, std::vector<AnnotationElement> elements)
|
||||
: record_name_(record_name), elements_(std::move(elements))
|
||||
{
|
||||
}
|
||||
|
||||
explicit AnnotationData(std::string_view record_name) : record_name_(record_name) {}
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(AnnotationData);
|
||||
DEFAULT_COPY_SEMANTIC(AnnotationData);
|
||||
|
||||
~AnnotationData() = default;
|
||||
|
||||
std::string GetName() const
|
||||
{
|
||||
return record_name_;
|
||||
}
|
||||
|
||||
const std::vector<AnnotationElement> &GetElements() const
|
||||
{
|
||||
return elements_;
|
||||
}
|
||||
|
||||
void AddElement(AnnotationElement &&element)
|
||||
{
|
||||
elements_.push_back(std::forward<AnnotationElement>(element));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string record_name_;
|
||||
std::vector<AnnotationElement> elements_;
|
||||
};
|
||||
|
||||
class ScalarValue;
|
||||
class ArrayValue;
|
||||
|
||||
class Value {
|
||||
public:
|
||||
enum class Type {
|
||||
U1,
|
||||
I8,
|
||||
U8,
|
||||
I16,
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
I64,
|
||||
U64,
|
||||
F32,
|
||||
F64,
|
||||
STRING,
|
||||
STRING_NULLPTR,
|
||||
RECORD,
|
||||
METHOD,
|
||||
ENUM,
|
||||
ANNOTATION,
|
||||
ARRAY,
|
||||
VOID,
|
||||
METHOD_HANDLE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
||||
static constexpr char GetTypeAsChar(Type t)
|
||||
{
|
||||
char type = '0';
|
||||
switch (t) {
|
||||
case Type::U1:
|
||||
type = '1';
|
||||
break;
|
||||
case Type::I8:
|
||||
type = '2';
|
||||
break;
|
||||
case Type::U8:
|
||||
type = '3';
|
||||
break;
|
||||
case Type::I16:
|
||||
type = '4';
|
||||
break;
|
||||
case Type::U16:
|
||||
type = '5';
|
||||
break;
|
||||
case Type::I32:
|
||||
type = '6';
|
||||
break;
|
||||
case Type::U32:
|
||||
type = '7';
|
||||
break;
|
||||
case Type::I64:
|
||||
type = '8';
|
||||
break;
|
||||
case Type::U64:
|
||||
type = '9';
|
||||
break;
|
||||
case Type::F32:
|
||||
type = 'A';
|
||||
break;
|
||||
case Type::F64:
|
||||
type = 'B';
|
||||
break;
|
||||
case Type::STRING:
|
||||
type = 'C';
|
||||
break;
|
||||
case Type::RECORD:
|
||||
type = 'D';
|
||||
break;
|
||||
case Type::METHOD:
|
||||
type = 'E';
|
||||
break;
|
||||
case Type::ENUM:
|
||||
type = 'F';
|
||||
break;
|
||||
case Type::ANNOTATION:
|
||||
type = 'G';
|
||||
break;
|
||||
case Type::ARRAY:
|
||||
type = 'H';
|
||||
break;
|
||||
case Type::VOID:
|
||||
type = 'I';
|
||||
break;
|
||||
case Type::METHOD_HANDLE:
|
||||
type = 'J';
|
||||
break;
|
||||
case Type::STRING_NULLPTR:
|
||||
type = '*';
|
||||
break;
|
||||
case Type::UNKNOWN:
|
||||
default:
|
||||
type = '0';
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
||||
static constexpr char GetArrayTypeAsChar(Type t)
|
||||
{
|
||||
char type = '0';
|
||||
switch (t) {
|
||||
case Type::U1:
|
||||
type = 'K';
|
||||
break;
|
||||
case Type::I8:
|
||||
type = 'L';
|
||||
break;
|
||||
case Type::U8:
|
||||
type = 'M';
|
||||
break;
|
||||
case Type::I16:
|
||||
type = 'N';
|
||||
break;
|
||||
case Type::U16:
|
||||
type = 'O';
|
||||
break;
|
||||
case Type::I32:
|
||||
type = 'P';
|
||||
break;
|
||||
case Type::U32:
|
||||
type = 'Q';
|
||||
break;
|
||||
case Type::I64:
|
||||
type = 'R';
|
||||
break;
|
||||
case Type::U64:
|
||||
type = 'S';
|
||||
break;
|
||||
case Type::F32:
|
||||
type = 'T';
|
||||
break;
|
||||
case Type::F64:
|
||||
type = 'U';
|
||||
break;
|
||||
case Type::STRING:
|
||||
type = 'V';
|
||||
break;
|
||||
case Type::RECORD:
|
||||
type = 'W';
|
||||
break;
|
||||
case Type::METHOD:
|
||||
type = 'X';
|
||||
break;
|
||||
case Type::ENUM:
|
||||
type = 'Y';
|
||||
break;
|
||||
case Type::ANNOTATION:
|
||||
type = 'Z';
|
||||
break;
|
||||
case Type::METHOD_HANDLE:
|
||||
type = '@';
|
||||
break;
|
||||
case Type::UNKNOWN:
|
||||
default:
|
||||
type = '0';
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
||||
static constexpr Type GetCharAsType(char c)
|
||||
{
|
||||
Type type = Type::UNKNOWN;
|
||||
switch (c) {
|
||||
case '1':
|
||||
type = Type::U1;
|
||||
break;
|
||||
case '2':
|
||||
type = Type::I8;
|
||||
break;
|
||||
case '3':
|
||||
type = Type::U8;
|
||||
break;
|
||||
case '4':
|
||||
type = Type::I16;
|
||||
break;
|
||||
case '5':
|
||||
type = Type::U16;
|
||||
break;
|
||||
case '6':
|
||||
type = Type::I32;
|
||||
break;
|
||||
case '7':
|
||||
type = Type::U32;
|
||||
break;
|
||||
case '8':
|
||||
type = Type::I64;
|
||||
break;
|
||||
case '9':
|
||||
type = Type::U64;
|
||||
break;
|
||||
case 'A':
|
||||
type = Type::F32;
|
||||
break;
|
||||
case 'B':
|
||||
type = Type::F64;
|
||||
break;
|
||||
case 'C':
|
||||
type = Type::STRING;
|
||||
break;
|
||||
case 'D':
|
||||
type = Type::RECORD;
|
||||
break;
|
||||
case 'E':
|
||||
type = Type::METHOD;
|
||||
break;
|
||||
case 'F':
|
||||
type = Type::ENUM;
|
||||
break;
|
||||
case 'G':
|
||||
type = Type::ANNOTATION;
|
||||
break;
|
||||
case 'H':
|
||||
type = Type::ARRAY;
|
||||
break;
|
||||
case 'I':
|
||||
type = Type::VOID;
|
||||
break;
|
||||
case 'J':
|
||||
type = Type::METHOD_HANDLE;
|
||||
break;
|
||||
case '*':
|
||||
type = Type::STRING_NULLPTR;
|
||||
break;
|
||||
case '0':
|
||||
default:
|
||||
type = Type::UNKNOWN;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
||||
static constexpr Type GetCharAsArrayType(char c)
|
||||
{
|
||||
Type type = Type::UNKNOWN;
|
||||
switch (c) {
|
||||
case 'K':
|
||||
type = Type::U1;
|
||||
break;
|
||||
case 'L':
|
||||
type = Type::I8;
|
||||
break;
|
||||
case 'M':
|
||||
type = Type::U8;
|
||||
break;
|
||||
case 'N':
|
||||
type = Type::I16;
|
||||
break;
|
||||
case 'O':
|
||||
type = Type::U16;
|
||||
break;
|
||||
case 'P':
|
||||
type = Type::I32;
|
||||
break;
|
||||
case 'Q':
|
||||
type = Type::U32;
|
||||
break;
|
||||
case 'R':
|
||||
type = Type::I64;
|
||||
break;
|
||||
case 'S':
|
||||
type = Type::U64;
|
||||
break;
|
||||
case 'T':
|
||||
type = Type::F32;
|
||||
break;
|
||||
case 'U':
|
||||
type = Type::F64;
|
||||
break;
|
||||
case 'V':
|
||||
type = Type::STRING;
|
||||
break;
|
||||
case 'W':
|
||||
type = Type::RECORD;
|
||||
break;
|
||||
case 'X':
|
||||
type = Type::METHOD;
|
||||
break;
|
||||
case 'Y':
|
||||
type = Type::ENUM;
|
||||
break;
|
||||
case 'Z':
|
||||
type = Type::ANNOTATION;
|
||||
break;
|
||||
case '@':
|
||||
type = Type::METHOD_HANDLE;
|
||||
break;
|
||||
case '0':
|
||||
default:
|
||||
type = Type::UNKNOWN;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
Type GetType() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
bool IsArray() const
|
||||
{
|
||||
return type_ == Type::ARRAY;
|
||||
}
|
||||
|
||||
ScalarValue *GetAsScalar();
|
||||
|
||||
const ScalarValue *GetAsScalar() const;
|
||||
|
||||
ArrayValue *GetAsArray();
|
||||
|
||||
const ArrayValue *GetAsArray() const;
|
||||
|
||||
virtual ~Value() = default;
|
||||
|
||||
DEFAULT_COPY_SEMANTIC(Value);
|
||||
DEFAULT_MOVE_SEMANTIC(Value);
|
||||
|
||||
protected:
|
||||
explicit Value(Type type) : type_(type) {}
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
|
||||
template <Value::Type value_type>
|
||||
struct ValueTypeHelper {
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
using type = std::conditional_t<value_type == Value::Type::U1, uint8_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::I8, int8_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::U8, uint8_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::I16, int16_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::U16, uint16_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::I32, int32_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::U32, uint32_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::I64, int64_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::U64, uint64_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::F32, float,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::F64, double,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::STRING, std::string_view,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::STRING_NULLPTR, uint32_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::RECORD, pandasm::Type,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::METHOD, std::string_view,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::ENUM, std::string_view,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<value_type == Value::Type::ANNOTATION, AnnotationData,
|
||||
void>>>>>>>>>>>>>>>>>;
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
template <Value::Type type>
|
||||
using ValueTypeHelperT = typename ValueTypeHelper<type>::type;
|
||||
|
||||
class ScalarValue : public Value {
|
||||
public:
|
||||
template <Value::Type type>
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
static ScalarValue Create(ValueTypeHelperT<type> value)
|
||||
{
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
using T = ValueTypeHelperT<type>;
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
return ScalarValue(type, static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (!std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
return ScalarValue(type, value);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T GetValue() const
|
||||
{
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
return static_cast<T>(std::get<uint64_t>(value_));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (!std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
return std::get<T>(value_);
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(ScalarValue);
|
||||
DEFAULT_COPY_SEMANTIC(ScalarValue);
|
||||
|
||||
~ScalarValue() override = default;
|
||||
|
||||
private:
|
||||
ScalarValue(Type type, uint64_t value) : Value(type), value_(value) {}
|
||||
|
||||
ScalarValue(Type type, float value) : Value(type), value_(value) {}
|
||||
|
||||
ScalarValue(Type type, double value) : Value(type), value_(value) {}
|
||||
|
||||
ScalarValue(Type type, std::string_view value) : Value(type), value_(std::string(value)) {}
|
||||
|
||||
ScalarValue(Type type, pandasm::Type value) : Value(type), value_(std::move(value)) {}
|
||||
|
||||
ScalarValue(Type type, const AnnotationData &value) : Value(type), value_(value) {}
|
||||
|
||||
std::variant<uint64_t, float, double, std::string, pandasm::Type, AnnotationData> value_;
|
||||
};
|
||||
|
||||
class ArrayValue : public Value {
|
||||
public:
|
||||
ArrayValue(Type component_type, std::vector<ScalarValue> values)
|
||||
: Value(Type::ARRAY), component_type_(component_type), values_(std::move(values))
|
||||
{
|
||||
}
|
||||
|
||||
NO_MOVE_SEMANTIC(ArrayValue);
|
||||
NO_COPY_SEMANTIC(ArrayValue);
|
||||
|
||||
~ArrayValue() override = default;
|
||||
|
||||
const std::vector<ScalarValue> &GetValues() const
|
||||
{
|
||||
return values_;
|
||||
}
|
||||
|
||||
Type GetComponentType() const
|
||||
{
|
||||
return component_type_;
|
||||
}
|
||||
|
||||
private:
|
||||
Type component_type_;
|
||||
std::vector<ScalarValue> values_;
|
||||
};
|
||||
|
||||
class AnnotationElement {
|
||||
public:
|
||||
AnnotationElement(std::string_view name, std::unique_ptr<Value> value) : name_(name), value_(std::move(value)) {}
|
||||
|
||||
AnnotationElement(const AnnotationElement &ann_elem);
|
||||
AnnotationElement &operator=(const AnnotationElement &ann_elem);
|
||||
DEFAULT_MOVE_SEMANTIC(AnnotationElement);
|
||||
~AnnotationElement() = default;
|
||||
|
||||
std::string GetName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
Value *GetValue() const
|
||||
{
|
||||
return value_.get();
|
||||
}
|
||||
|
||||
static std::string TypeToString(Value::Type type);
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::unique_ptr<Value> value_;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ANNOTATION_H_
|
||||
Executable
+124
@@ -0,0 +1,124 @@
|
||||
# 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.
|
||||
|
||||
# Assembler-specific extension of ISAPI
|
||||
Instruction.class_eval do
|
||||
def asm_token
|
||||
mnemonic.tr('.', '_').upcase
|
||||
end
|
||||
|
||||
def builtin?
|
||||
%w[builtin].include?(stripped_mnemonic)
|
||||
end
|
||||
|
||||
def builtin_idr4?
|
||||
builtin? && mnemonic.split('.')[-1] == 'idr4'
|
||||
end
|
||||
|
||||
def builtin_idr6?
|
||||
builtin? && mnemonic.split('.')[-1] == 'idr6'
|
||||
end
|
||||
|
||||
def call?
|
||||
%w[call initobj].include?(stripped_mnemonic)
|
||||
end
|
||||
|
||||
def calli?
|
||||
%w[calli].include?(stripped_mnemonic)
|
||||
end
|
||||
|
||||
def call_range?
|
||||
call? && mnemonic.split('.')[-1] == 'range'
|
||||
end
|
||||
|
||||
def calli_range?
|
||||
calli? && mnemonic.split('.')[-1] == 'range'
|
||||
end
|
||||
|
||||
def simple_call?
|
||||
(call? || calli?) && !call_range?
|
||||
end
|
||||
|
||||
def return?
|
||||
stripped_mnemonic == 'return'
|
||||
end
|
||||
|
||||
def return_obj?
|
||||
mnemonic == 'return.obj'
|
||||
end
|
||||
|
||||
def return64?
|
||||
mnemonic == 'return.64'
|
||||
end
|
||||
|
||||
def return32?
|
||||
mnemonic == 'return'
|
||||
end
|
||||
|
||||
def return_void?
|
||||
mnemonic == 'return.void'
|
||||
end
|
||||
end
|
||||
|
||||
def bit_cast(what, to_type, from_type)
|
||||
"bit_cast<#{to_type}, #{from_type}>(static_cast<#{from_type}>(std::get<double>(#{what})))"
|
||||
end
|
||||
|
||||
def index_of_max(a)
|
||||
a.each_with_index.max[1] # returns index of `last` max value
|
||||
end
|
||||
|
||||
def max_number_of_src_regs
|
||||
Panda::instructions.map do |insn|
|
||||
insn.operands.select(&:reg?).select(&:src?).size
|
||||
end.max
|
||||
end
|
||||
|
||||
IR = Struct.new(:opcode, :flags, :dst_idx, :use_idxs)
|
||||
|
||||
module Panda
|
||||
def self.pseudo_instructions
|
||||
insns = []
|
||||
insns << IR.new('MOVX', ['InstFlags::PSEUDO'], 0, [1])
|
||||
insns << IR.new('LDAX', ['InstFlags::PSEUDO', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [0])
|
||||
insns << IR.new('STAX', ['InstFlags::PSEUDO', 'InstFlags::ACC_READ'], 0, [])
|
||||
insns << IR.new('NEWX', ['InstFlags::PSEUDO'], 0, [])
|
||||
insns << IR.new('INITOBJX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('CALLX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('CALLX_VIRT', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('B_P_CALLIX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_READ'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('B_P_CALLIEX',['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_READ'], 'INVALID_REG_IDX', [])
|
||||
insns
|
||||
end
|
||||
end
|
||||
|
||||
# returns array of OpenStruct with fields
|
||||
# name - name of variable in emitter code
|
||||
# type - type of variable in emitter code
|
||||
def assembler_signature(group, is_jump)
|
||||
insn = group.first
|
||||
sig = format_ops(insn.format)
|
||||
sig.each_with_index do |o, i|
|
||||
if o.name.start_with?('imm')
|
||||
if insn.asm_token.start_with?('F')
|
||||
o.type, o.name = is_jump ? ['const std::string &', 'label'] : ["double", o.name]
|
||||
else
|
||||
o.type, o.name = is_jump ? ['const std::string &', 'label'] : ["int64_t", o.name]
|
||||
end
|
||||
elsif o.name.start_with?('id')
|
||||
o.type, o.name = ['const std::string &', 'id']
|
||||
else
|
||||
o.type = "uint16_t"
|
||||
end
|
||||
end
|
||||
end
|
||||
Executable
+248
@@ -0,0 +1,248 @@
|
||||
# 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.
|
||||
|
||||
require 'delegate'
|
||||
|
||||
class Attritute < SimpleDelegator
|
||||
def getter_name
|
||||
r = name.capitalize
|
||||
type == 'bool' ? 'Is' + r : 'Get' + r
|
||||
end
|
||||
|
||||
def setter_name
|
||||
'Set' + name.capitalize
|
||||
end
|
||||
|
||||
def bool?
|
||||
type == 'bool'
|
||||
end
|
||||
|
||||
def enum?
|
||||
type == 'enum'
|
||||
end
|
||||
|
||||
def size?
|
||||
type == 'size'
|
||||
end
|
||||
|
||||
def multiple?
|
||||
!bool? && multiple
|
||||
end
|
||||
|
||||
def applicable_to?(item_type)
|
||||
applicable_to.include?(item_type)
|
||||
end
|
||||
|
||||
def set_flags?
|
||||
(defined? flags) && flags.any? || enum? && values.any? { |v| v.flags && v.flags.any? }
|
||||
end
|
||||
end
|
||||
|
||||
module Metadata
|
||||
module_function
|
||||
|
||||
def attributes
|
||||
@data.attributes.map do |op|
|
||||
Attritute.new(op)
|
||||
end
|
||||
end
|
||||
|
||||
def language
|
||||
@data.language || ''
|
||||
end
|
||||
|
||||
def extends_default?
|
||||
!language.empty?
|
||||
end
|
||||
|
||||
def item_types
|
||||
['record', 'field', 'function', 'param']
|
||||
end
|
||||
|
||||
def wrap_data(data)
|
||||
@data = data
|
||||
end
|
||||
end
|
||||
|
||||
def Gen.on_require(data)
|
||||
Metadata.wrap_data(data)
|
||||
end
|
||||
|
||||
module MetadataGen
|
||||
module_function
|
||||
|
||||
def attribute_name(attribute)
|
||||
return attribute.name if Metadata.language.empty?
|
||||
"#{Metadata.language.downcase}.#{attribute.name}"
|
||||
end
|
||||
|
||||
def class_name(item_type)
|
||||
item_type.capitalize + 'Metadata'
|
||||
end
|
||||
|
||||
def validate_body(item_type, is_bool)
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool }
|
||||
body = []
|
||||
indent = ' ' * 4
|
||||
|
||||
attributes.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
|
||||
unless a.multiple?
|
||||
body << "#{indent * 2}if (HasAttribute(attribute)) {"
|
||||
body << "#{indent * 3}return Error(\"Attribute '#{attribute_name(a)}' already defined\","
|
||||
body << "#{indent * 3} Error::Type::MULTIPLE_ATTRIBUTE);"
|
||||
body << "#{indent * 2}}"
|
||||
end
|
||||
|
||||
if a.enum?
|
||||
a.values.each do |v|
|
||||
body << "#{indent * 2}if (value == \"#{v.value}\") {"
|
||||
body << "#{indent * 3}return {};"
|
||||
body << "#{indent * 2}}"
|
||||
body << ""
|
||||
end
|
||||
|
||||
body << "#{indent * 2}return Error(std::string(\"Attribute '#{attribute_name(a)}' has incorrect value '\").append(value) +"
|
||||
body << "#{indent * 2} R\"('. Should be one of #{a.values.map(&:value)})\", Error::Type::INVALID_VALUE);"
|
||||
elsif a.size?
|
||||
body << "#{indent * 2}return ValidateSize(value);"
|
||||
else
|
||||
body << "#{indent * 2}return {};"
|
||||
end
|
||||
|
||||
body << "#{indent}}"
|
||||
body << ""
|
||||
end
|
||||
|
||||
Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? != is_bool }.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
body << "#{indent * 2}return Error(\"Attribute '#{attribute_name(a)}' #{is_bool ? "must" : "must not"} have a value\","
|
||||
body << "#{indent * 2} #{is_bool ? "Error::Type::MISSING_VALUE" : "Error::Type::UNEXPECTED_VALUE"});"
|
||||
body << "#{indent}}"
|
||||
body << ""
|
||||
end
|
||||
|
||||
if Metadata::extends_default?
|
||||
args = ['attribute']
|
||||
args << 'value' unless is_bool
|
||||
body << "#{indent}return pandasm::#{class_name(item_type)}::Validate(#{args.join(', ')});"
|
||||
else
|
||||
body << "#{indent}return Error(std::string(\"Unknown attribute '\").append(attribute) + \"'\","
|
||||
body << "#{indent} Error::Type::UNKNOWN_ATTRIBUTE);"
|
||||
end
|
||||
|
||||
body
|
||||
end
|
||||
|
||||
def set_flags_body(item_type, is_bool)
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? }
|
||||
body = []
|
||||
indent = ' ' * 4
|
||||
|
||||
attributes.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
|
||||
if defined? a.flags
|
||||
body << "#{indent * 2}SetAccessFlags(GetAccessFlags() | #{a.flags.join(' | ')});"
|
||||
end
|
||||
|
||||
if a.enum?
|
||||
a.values.select { |v| v.flags && v.flags.any? }.each do |v|
|
||||
body << "#{indent * 2}if (value == \"#{v.value}\") {"
|
||||
body << "#{indent * 3}SetAccessFlags(GetAccessFlags() | #{v.flags.join(' | ')});"
|
||||
body << "#{indent * 2}}"
|
||||
body << ""
|
||||
end
|
||||
end
|
||||
|
||||
body << "#{indent}}"
|
||||
end
|
||||
|
||||
if Metadata::extends_default?
|
||||
args = ['attribute']
|
||||
args << 'value' unless is_bool
|
||||
body << "#{indent}pandasm::#{class_name(item_type)}::SetFlags(#{args.join(', ')});"
|
||||
end
|
||||
|
||||
body
|
||||
end
|
||||
|
||||
def remove_flags_body(item_type, is_bool)
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? }
|
||||
body = []
|
||||
indent = ' ' * 4
|
||||
|
||||
attributes.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
|
||||
if defined? a.flags
|
||||
body << "#{indent * 2}if ((GetAccessFlags() & #{a.flags.join(' | ')}) != 0) {"
|
||||
body << "#{indent * 3}SetAccessFlags(GetAccessFlags() ^ (#{a.flags.join(' | ')}));"
|
||||
body << "#{indent * 2}}"
|
||||
end
|
||||
|
||||
if a.enum?
|
||||
a.values.select { |v| v.flags && v.flags.any? }.each do |v|
|
||||
body << "#{indent * 2}if (value == \"#{v.value}\") {"
|
||||
body << "#{indent * 3}if ((GetAccessFlags() & (#{v.flags.join(' | ')})) != 0) {"
|
||||
body << "#{indent * 4}SetAccessFlags(GetAccessFlags() ^ (#{v.flags.join(' | ')}));"
|
||||
body << "#{indent * 3}}"
|
||||
body << "#{indent * 2}}"
|
||||
end
|
||||
end
|
||||
|
||||
body << "#{indent}}"
|
||||
end
|
||||
|
||||
if Metadata::extends_default?
|
||||
args = ['attribute']
|
||||
args << 'value' unless is_bool
|
||||
body << "#{indent}pandasm::#{class_name(item_type)}::RemoveFlags(#{args.join(', ')});"
|
||||
end
|
||||
|
||||
body
|
||||
end
|
||||
|
||||
def arg_list(is_bool)
|
||||
args = ['std::string_view attribute']
|
||||
args << 'std::string_view value' if !is_bool
|
||||
args
|
||||
end
|
||||
|
||||
def add_unused_attribute(arg)
|
||||
"[[maybe_unused]] #{arg}"
|
||||
end
|
||||
|
||||
def validate_arg_list(item_type, is_bool)
|
||||
args = arg_list(is_bool)
|
||||
return args if Metadata::extends_default?
|
||||
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool }
|
||||
args[0] = add_unused_attribute(args[0]) if attributes.none?
|
||||
args[1] = add_unused_attribute(args[1]) if args[1] && attributes.none? { |a| a.enum? }
|
||||
args
|
||||
end
|
||||
|
||||
def flags_arg_list(item_type, is_bool)
|
||||
args = arg_list(is_bool)
|
||||
return args if Metadata::extends_default?
|
||||
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? }
|
||||
use_value = attributes.any? { |a| a.enum? && a.values.any? { |v| v.flags && v.flags.any? } }
|
||||
args[0] = add_unused_attribute(args[0]) if attributes.none?
|
||||
args[1] = add_unused_attribute(args[1]) if args[1] && !use_value
|
||||
args
|
||||
end
|
||||
|
||||
end
|
||||
@@ -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 PANDA_ASSEMBLER_ASSEMBLY_CONTEXT_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_CONTEXT_H_
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-type.h"
|
||||
#include "error.h"
|
||||
#include "lexer.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
/*
|
||||
* Used to move around tokens.
|
||||
* *context :
|
||||
* returns current value of a token
|
||||
* ++context :
|
||||
* sets the next token value
|
||||
* returns current value of a token
|
||||
* context++ :
|
||||
* sets the next token value
|
||||
* returns the next value of a token
|
||||
* similarly --context and context--
|
||||
*/
|
||||
struct Context {
|
||||
std::string_view token; /* current token */
|
||||
std::vector<panda::pandasm::Token> tokens; /* token list */
|
||||
size_t number = 0; /* line number */
|
||||
bool end = false; /* end of line flag */
|
||||
Token::Type id = Token::Type::ID_BAD; /* current token type */
|
||||
Token::Type signop = Token::Type::ID_BAD; /* current token operand type (if it is an operation) */
|
||||
panda::pandasm::Error err; /* current error */
|
||||
int64_t *max_value_of_reg = nullptr;
|
||||
size_t ins_number = 0;
|
||||
Type curr_func_return_type;
|
||||
std::vector<std::pair<size_t, size_t>> *function_arguments_list = nullptr;
|
||||
std::unordered_map<std::string, std::vector<std::pair<size_t, size_t>>> function_arguments_lists;
|
||||
|
||||
void Make(const std::vector<panda::pandasm::Token> &t);
|
||||
void UpSignOperation();
|
||||
bool ValidateRegisterName(char c, size_t n = 0) const;
|
||||
bool ValidateParameterName(size_t number_of_params_already_is) const;
|
||||
bool ValidateLabel();
|
||||
bool Mask();
|
||||
bool NextMask();
|
||||
size_t Len() const;
|
||||
std::string_view GiveToken();
|
||||
Token::Type WaitFor();
|
||||
Token::Type Next();
|
||||
|
||||
Token::Type operator++(int);
|
||||
Token::Type operator--(int);
|
||||
Token::Type operator++();
|
||||
Token::Type operator--();
|
||||
Token::Type operator*();
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_CONTEXT_H_
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_DEBUG_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_DEBUG_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace panda::pandasm::debuginfo {
|
||||
|
||||
struct Ins {
|
||||
size_t line_number = 0;
|
||||
std::string whole_line = "";
|
||||
size_t bound_left = 0;
|
||||
size_t bound_right = 0;
|
||||
|
||||
void SetLineNumber(size_t ln)
|
||||
{
|
||||
line_number = ln;
|
||||
}
|
||||
|
||||
Ins() = default;
|
||||
Ins(size_t l_n, std::string &f_c, size_t b_l, size_t b_r)
|
||||
: line_number(l_n), whole_line(std::move(f_c)), bound_left(b_l), bound_right(b_r)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct LocalVariable {
|
||||
std::string name;
|
||||
std::string signature;
|
||||
std::string signature_type;
|
||||
int32_t reg = 0;
|
||||
uint32_t start = 0;
|
||||
uint32_t length = 0;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm::debuginfo
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_DEBUG_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_EMITTER_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_EMITTER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-literals.h"
|
||||
#include "assembly-program.h"
|
||||
#include "assembly-type.h"
|
||||
#include "assembly-function.h"
|
||||
#include "bytecode_emitter.h"
|
||||
#include "file_item_container.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class AsmEmitter {
|
||||
public:
|
||||
struct PandaFileToPandaAsmMaps {
|
||||
std::unordered_map<uint32_t, std::string> methods;
|
||||
std::unordered_map<uint32_t, std::string> fields;
|
||||
std::unordered_map<uint32_t, std::string> classes;
|
||||
std::unordered_map<uint32_t, std::string> strings;
|
||||
std::unordered_map<uint32_t, std::string> literalarrays;
|
||||
};
|
||||
|
||||
struct AsmEntityCollections {
|
||||
std::unordered_map<std::string, panda_file::BaseMethodItem *> method_items;
|
||||
std::unordered_map<std::string, panda_file::BaseFieldItem *> field_items;
|
||||
std::unordered_map<std::string, panda_file::BaseClassItem *> class_items;
|
||||
std::unordered_map<std::string_view, panda_file::StringItem *> string_items;
|
||||
std::unordered_map<std::string, panda_file::LiteralArrayItem *> literalarray_items;
|
||||
};
|
||||
|
||||
static bool Emit(panda_file::ItemContainer *items, const Program &program, PandaFileToPandaAsmMaps *maps = nullptr,
|
||||
bool emit_debug_info = true);
|
||||
|
||||
static bool Emit(panda_file::Writer *writer, const Program &program, std::map<std::string, size_t> *stat = nullptr,
|
||||
PandaFileToPandaAsmMaps *maps = nullptr, bool debug_info = true);
|
||||
|
||||
static bool Emit(const std::string &filename, const Program &program, std::map<std::string, size_t> *stat = nullptr,
|
||||
PandaFileToPandaAsmMaps *maps = nullptr, bool debug_info = true);
|
||||
|
||||
static std::unique_ptr<const panda_file::File> Emit(const Program &program,
|
||||
PandaFileToPandaAsmMaps *maps = nullptr);
|
||||
|
||||
static std::string GetLastError()
|
||||
{
|
||||
return last_error;
|
||||
}
|
||||
|
||||
private:
|
||||
static void MakeStringItems(panda_file::ItemContainer *items, const Program &program,
|
||||
AsmEntityCollections &entities);
|
||||
static void MakeLiteralItems(panda_file::ItemContainer *items, const Program &program,
|
||||
AsmEmitter::AsmEntityCollections &entities);
|
||||
static void MakeArrayTypeItems(panda_file::ItemContainer *items, const Program &program,
|
||||
AsmEntityCollections &entities);
|
||||
static bool HandleRecordAsForeign(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const std::string &name, const Record &rec);
|
||||
static bool HandleBaseRecord(panda_file::ItemContainer *items, const Program &program, const std::string &name,
|
||||
const Record &rec, panda_file::ClassItem *record);
|
||||
static bool HandleInterfaces(panda_file::ItemContainer *items, const Program &program, const std::string &name,
|
||||
const Record &rec, panda_file::ClassItem *record);
|
||||
static bool HandleFields(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const std::string &name, const Record &rec, panda_file::ClassItem *record);
|
||||
static bool HandleRecord(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const std::string &name, const Record &rec);
|
||||
static bool MakeRecordItems(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types);
|
||||
static panda_file::StringItem *GetMethodName(panda_file::ItemContainer *items, const Function &func,
|
||||
const std::string &name);
|
||||
static bool HandleAreaForInner(panda_file::ItemContainer *items, const Program &program,
|
||||
panda_file::ClassItem **area, panda_file::ForeignClassItem **foreign_area,
|
||||
const std::string &name, const std::string &record_owner_name);
|
||||
static bool HandleRecordOnwer(panda_file::ItemContainer *items, const Program &program,
|
||||
panda_file::ClassItem **area, panda_file::ForeignClassItem **foreign_area,
|
||||
const std::string &name, const std::string &record_owner_name);
|
||||
static bool HandleFunctionParams(
|
||||
panda_file::ItemContainer *items, const Program &program, size_t idx, const std::string &name,
|
||||
const Function &func,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
std::vector<panda_file::MethodParamItem> ¶ms);
|
||||
static bool HandleFunctionLocalVariables(panda_file::ItemContainer *items, const Function &func,
|
||||
const std::string &name);
|
||||
static bool CreateMethodItem(panda_file::ItemContainer *items, AsmEmitter::AsmEntityCollections &entities,
|
||||
const Function &func, panda_file::TypeItem *type_item, panda_file::ClassItem *area,
|
||||
panda_file::ForeignClassItem *foreign_area, uint32_t access_flags,
|
||||
panda_file::StringItem *method_name, const std::string &mangled_name,
|
||||
const std::string &name, std::vector<panda_file::MethodParamItem> ¶ms);
|
||||
static bool MakeFunctionItems(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
bool emit_debug_info);
|
||||
static bool MakeRecordAnnotations(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEntityCollections &entities);
|
||||
static void SetCodeAndDebugInfo(panda_file::ItemContainer *items, panda_file::MethodItem *method,
|
||||
const Function &func, bool emit_debug_info);
|
||||
static void SetMethodSourceLang(const Program &program, panda_file::MethodItem *method, const Function &func,
|
||||
const std::string &name);
|
||||
static bool AddMethodAndParamsAnnotations(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEmitter::AsmEntityCollections &entities,
|
||||
panda_file::MethodItem *method, const Function &func);
|
||||
static bool MakeFunctionDebugInfoAndAnnotations(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEntityCollections &entities, bool emit_debug_info);
|
||||
static void FillMap(PandaFileToPandaAsmMaps *maps, const AsmEntityCollections &entities);
|
||||
static void EmitDebugInfo(panda_file::ItemContainer *items, const Program &program,
|
||||
const std::vector<uint8_t> *bytes, const panda_file::MethodItem *method,
|
||||
const Function &func, const std::string &name, bool emit_debug_info);
|
||||
static bool EmitFunctions(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEntityCollections &entities, bool emit_debug_info);
|
||||
|
||||
static panda_file::TypeItem *GetTypeItem(
|
||||
panda_file::ItemContainer *items,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const Type &type, const Program &program);
|
||||
|
||||
static void SetLastError(const std::string &message)
|
||||
{
|
||||
last_error = message;
|
||||
}
|
||||
|
||||
static bool CheckValueType(Value::Type value_type, Type type, const Program &program);
|
||||
|
||||
static bool CheckValueEnumCase(const Value *value, Type type, const Program &program);
|
||||
static bool CheckValueArrayCase(const Value *value, Type type, const Program &program);
|
||||
static bool CheckValueMethodCase(const Value *value, const Program &program);
|
||||
static bool CheckValueRecordCase(const Value *value, const Program &program);
|
||||
static bool CheckValue(const Value *value, Type type, const Program &program);
|
||||
|
||||
static panda_file::LiteralItem *CreateLiteralItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::LiteralItem> *out,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
template <class PrimType>
|
||||
static panda_file::ScalarValueItem *CreateScalarPrimValueItem(panda_file::ItemContainer *container,
|
||||
const Value *value,
|
||||
std::vector<panda_file::ScalarValueItem> *out)
|
||||
{
|
||||
static_assert(std::is_arithmetic<PrimType>::value);
|
||||
auto v = value->GetAsScalar()->GetValue<PrimType>();
|
||||
if (out != nullptr) {
|
||||
out->emplace_back(v);
|
||||
return &out->back();
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<PrimType, uint32_t>::value) {
|
||||
return container->GetOrCreateIntegerValueItem(v);
|
||||
} else if constexpr (std::is_same<PrimType, uint64_t>::value) {
|
||||
return container->GetOrCreateLongValueItem(v);
|
||||
} else if constexpr (std::is_same<PrimType, float>::value) {
|
||||
return container->GetOrCreateFloatValueItem(v);
|
||||
} else if constexpr (std::is_same<PrimType, double>::value) {
|
||||
return container->GetOrCreateDoubleValueItem(v);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static panda_file::ScalarValueItem *CreateScalarStringValueItem(panda_file::ItemContainer *container,
|
||||
const Value *value,
|
||||
std::vector<panda_file::ScalarValueItem> *out);
|
||||
static panda_file::ScalarValueItem *CreateScalarRecordValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes);
|
||||
static panda_file::ScalarValueItem *CreateScalarMethodValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
static panda_file::ScalarValueItem *CreateScalarEnumValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields);
|
||||
static panda_file::ScalarValueItem *CreateScalarAnnotationValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const Program &program, const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::ScalarValueItem *CreateScalarValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const Program &program, const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::ValueItem *CreateValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, const Program &program,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::AnnotationItem *CreateAnnotationItem(
|
||||
panda_file::ItemContainer *container, const AnnotationData &annotation, const Program &program,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::MethodHandleItem *CreateMethodHandleItem(
|
||||
panda_file::ItemContainer *container, const MethodHandle &mh,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
template <class T>
|
||||
static bool AddAnnotations(T *item, panda_file::ItemContainer *container, const AnnotationMetadata &metadata,
|
||||
const Program &program,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static std::string last_error;
|
||||
};
|
||||
|
||||
std::string GetOwnerName(const std::string &name);
|
||||
std::string GetItemName(const std::string &name);
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_EMITTER_H_
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_FIELD_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_FIELD_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "assembly-type.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "meta.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Field {
|
||||
Type type;
|
||||
std::string name;
|
||||
std::unique_ptr<FieldMetadata> metadata;
|
||||
size_t line_of_def = 0;
|
||||
std::string whole_line = ""; /* The line in which the field is defined */
|
||||
/* Or line in which the field is met, if the field is not defined */
|
||||
size_t bound_left = 0;
|
||||
size_t bound_right = 0;
|
||||
bool is_defined = true;
|
||||
|
||||
explicit Field(extensions::Language lang) : metadata(extensions::MetadataExtension::CreateFieldMetadata(lang)) {}
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_FIELD_H_
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_FILE_LOCATION_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_FILE_LOCATION_H_
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class FileLocation {
|
||||
public:
|
||||
std::string whole_line = ""; /* The line in which the field is defined */
|
||||
/* Or line in which the field is met, if the field is not defined */
|
||||
size_t bound_left = 0;
|
||||
size_t bound_right = 0;
|
||||
size_t line_number = 0;
|
||||
bool is_defined = false;
|
||||
|
||||
public:
|
||||
FileLocation(std::string &f_c, size_t b_l, size_t b_r, size_t l_n, bool d)
|
||||
: whole_line(std::move(f_c)), bound_left(b_l), bound_right(b_r), line_number(l_n), is_defined(d)
|
||||
{
|
||||
}
|
||||
~FileLocation() = default;
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(FileLocation);
|
||||
DEFAULT_COPY_SEMANTIC(FileLocation);
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_FILE_LOCATION_H_
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_FUNCTION_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_FUNCTION_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-label.h"
|
||||
#include "assembly-type.h"
|
||||
#include "assembly-debug.h"
|
||||
#include "assembly-file-location.h"
|
||||
#include "bytecode_emitter.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "file_items.h"
|
||||
#include "file_item_container.h"
|
||||
#include "ide_helpers.h"
|
||||
#include "meta.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Function {
|
||||
struct CatchBlock {
|
||||
std::string whole_line;
|
||||
std::string exception_record;
|
||||
std::string try_begin_label;
|
||||
std::string try_end_label;
|
||||
std::string catch_begin_label;
|
||||
std::string catch_end_label;
|
||||
};
|
||||
|
||||
struct TryCatchInfo {
|
||||
std::unordered_map<std::string_view, size_t> try_catch_labels;
|
||||
std::unordered_map<std::string, std::vector<const CatchBlock *>> try_catch_map;
|
||||
std::vector<std::string> try_catch_order;
|
||||
TryCatchInfo(std::unordered_map<std::string_view, size_t> &labels,
|
||||
std::unordered_map<std::string, std::vector<const CatchBlock *>> &map,
|
||||
std::vector<std::string> ¶m_try_catch_order)
|
||||
: try_catch_labels(labels), try_catch_map(map), try_catch_order(param_try_catch_order)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Parameter {
|
||||
Type type;
|
||||
std::unique_ptr<ParamMetadata> metadata;
|
||||
|
||||
Parameter(Type t, extensions::Language lang)
|
||||
: type(std::move(t)), metadata(extensions::MetadataExtension::CreateParamMetadata(lang))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::string name = "";
|
||||
extensions::Language language;
|
||||
std::unique_ptr<FunctionMetadata> metadata;
|
||||
|
||||
std::unordered_map<std::string, panda::pandasm::Label> label_table;
|
||||
std::vector<panda::pandasm::Ins> ins; /* function instruction list */
|
||||
std::vector<panda::pandasm::debuginfo::LocalVariable> local_variable_debug;
|
||||
std::string source_file; /* The file in which the function is defined or empty */
|
||||
std::string source_code;
|
||||
std::vector<CatchBlock> catch_blocks;
|
||||
int64_t value_of_first_param = -1;
|
||||
size_t regs_num = 0;
|
||||
std::vector<Parameter> params;
|
||||
bool body_presence = false;
|
||||
Type return_type;
|
||||
SourceLocation body_location;
|
||||
std::optional<FileLocation> file_location;
|
||||
|
||||
void SetInsDebug(const std::vector<debuginfo::Ins> &ins_debug)
|
||||
{
|
||||
ASSERT(ins_debug.size() == ins.size());
|
||||
for (std::size_t i = 0; i < ins.size(); i++) {
|
||||
ins[i].ins_debug = ins_debug[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AddInstruction(const panda::pandasm::Ins &instruction)
|
||||
{
|
||||
ins.emplace_back(instruction);
|
||||
}
|
||||
|
||||
Function(std::string s, extensions::Language lang, size_t b_l, size_t b_r, std::string f_c, bool d, size_t l_n)
|
||||
: name(std::move(s)),
|
||||
language(lang),
|
||||
metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang)),
|
||||
file_location({f_c, b_l, b_r, l_n, d})
|
||||
{
|
||||
}
|
||||
|
||||
Function(std::string s, extensions::Language lang)
|
||||
: name(std::move(s)), language(lang), metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang))
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t GetParamsNum() const
|
||||
{
|
||||
return params.size();
|
||||
}
|
||||
|
||||
bool IsStatic() const
|
||||
{
|
||||
return (metadata->GetAccessFlags() & ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
|
||||
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays) const;
|
||||
|
||||
size_t GetLineNumber(size_t i) const;
|
||||
|
||||
void EmitLocalVariable(panda_file::LineNumberProgramItem *program, panda_file::ItemContainer *container,
|
||||
std::vector<uint8_t> *constant_pool, uint32_t &pc_inc, size_t instruction_number) const;
|
||||
void EmitNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool, uint32_t pc_inc,
|
||||
int32_t line_inc) const;
|
||||
void EmitLineNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
|
||||
int32_t &prev_line_number, uint32_t &pc_inc, size_t instruction_number) const;
|
||||
|
||||
void BuildLineNumberProgram(panda_file::DebugInfoItem *debug_item, const std::vector<uint8_t> &bytecode,
|
||||
panda_file::ItemContainer *container, std::vector<uint8_t> *constant_pool,
|
||||
bool emit_debug_info) const;
|
||||
|
||||
Function::TryCatchInfo MakeOrderAndOffsets(const std::vector<uint8_t> &bytecode) const;
|
||||
|
||||
std::vector<panda_file::CodeItem::TryBlock> BuildTryBlocks(
|
||||
panda_file::MethodItem *method, const std::unordered_map<std::string, panda_file::BaseClassItem *> &class_items,
|
||||
const std::vector<uint8_t> &bytecode) const;
|
||||
|
||||
bool HasImplementation() const
|
||||
{
|
||||
return !metadata->IsForeign() && metadata->HasImplementation();
|
||||
}
|
||||
|
||||
bool IsParameter(uint32_t reg_number) const
|
||||
{
|
||||
return reg_number >= regs_num;
|
||||
}
|
||||
|
||||
bool CanThrow() const
|
||||
{
|
||||
return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.CanThrow(); });
|
||||
}
|
||||
|
||||
bool HasDebugInfo() const
|
||||
{
|
||||
return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.HasDebugInfo(); });
|
||||
}
|
||||
|
||||
void DebugDump() const;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_FUNCTION_H_
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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 <iostream>
|
||||
#include "assembly-ins.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::string panda::pandasm::Ins::RegsToString(bool &first, bool print_args, size_t first_arg_idx) const
|
||||
{
|
||||
std::stringstream translator;
|
||||
for (const auto ® : this->regs) {
|
||||
if (!first) {
|
||||
translator << ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (print_args && reg >= first_arg_idx) {
|
||||
translator << " a" << reg - first_arg_idx;
|
||||
} else {
|
||||
translator << " v" << reg;
|
||||
}
|
||||
}
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::ImmsToString(bool &first) const
|
||||
{
|
||||
std::stringstream translator;
|
||||
for (const auto &imm : this->imms) {
|
||||
if (!first) {
|
||||
translator << ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
auto *number = std::get_if<double>(&imm);
|
||||
if (number != nullptr) {
|
||||
translator << " " << std::scientific << *number;
|
||||
} else {
|
||||
translator << " 0x" << std::hex << std::get<int64_t>(imm);
|
||||
}
|
||||
translator.clear();
|
||||
}
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::IdsToString(bool &first) const
|
||||
{
|
||||
std::stringstream translator;
|
||||
for (const auto &id : this->ids) {
|
||||
if (!first) {
|
||||
translator << ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
translator << " " << id;
|
||||
}
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::OperandsToString(PrintKind print_kind, bool print_args, size_t first_arg_idx) const
|
||||
{
|
||||
bool first = true;
|
||||
std::stringstream ss {};
|
||||
|
||||
switch (print_kind) {
|
||||
case PrintKind::CALL:
|
||||
ss << this->IdsToString(first) << this->RegsToString(first, print_args, first_arg_idx);
|
||||
if (!imms.empty()) {
|
||||
ss << ImmsToString(first);
|
||||
}
|
||||
break;
|
||||
case PrintKind::CALLI:
|
||||
ss << this->IdsToString(first) << this->ImmsToString(first)
|
||||
<< this->RegsToString(first, print_args, first_arg_idx);
|
||||
break;
|
||||
case PrintKind::DEFAULT:
|
||||
default:
|
||||
ss << this->RegsToString(first, print_args, first_arg_idx) << this->ImmsToString(first)
|
||||
<< this->IdsToString(first);
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_INS_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_INS_H_
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-debug.h"
|
||||
#include "bytecode_emitter.h"
|
||||
#include "file_items.h"
|
||||
#include "isa.h"
|
||||
#include "lexer.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
enum class Opcode {
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) opcode,
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)
|
||||
#undef OPLIST
|
||||
INVALID,
|
||||
NUM_OPCODES = INVALID
|
||||
};
|
||||
|
||||
enum InstFlags {
|
||||
NONE = 0,
|
||||
JUMP = (1U << 0U),
|
||||
COND = (1U << 1U),
|
||||
CALL = (1U << 2U),
|
||||
RETURN = (1U << 3U),
|
||||
ACC_READ = (1U << 4U),
|
||||
ACC_WRITE = (1U << 5U),
|
||||
PSEUDO = (1U << 6U),
|
||||
THROWING = (1U << 7U),
|
||||
METHOD_ID = (1U << 8U),
|
||||
FIELD_ID = (1U << 9U),
|
||||
TYPE_ID = (1U << 10U),
|
||||
STRING_ID = (1U << 11U),
|
||||
LITERALARRAY_ID = (1U << 12U)
|
||||
};
|
||||
|
||||
enum class PrintKind { DEFAULT, CALL, CALLI };
|
||||
|
||||
constexpr int INVALID_REG_IDX = -1;
|
||||
constexpr size_t MAX_NUMBER_OF_SRC_REGS = 5;
|
||||
constexpr size_t NUM_OPCODES = static_cast<size_t>(Opcode::NUM_OPCODES);
|
||||
|
||||
constexpr InstFlags operator|(InstFlags a, InstFlags b)
|
||||
{
|
||||
using utype = std::underlying_type_t<InstFlags>;
|
||||
return static_cast<InstFlags>(static_cast<utype>(a) | static_cast<utype>(b));
|
||||
}
|
||||
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) flags,
|
||||
constexpr std::array<unsigned, NUM_OPCODES> INST_FLAGS_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
#undef OPLIST
|
||||
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) width,
|
||||
constexpr std::array<size_t, NUM_OPCODES> INST_WIDTH_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
#undef OPLIST
|
||||
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) def_idx,
|
||||
constexpr std::array<int, NUM_OPCODES> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
#undef OPLIST
|
||||
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) use_idxs,
|
||||
constexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>, NUM_OPCODES> USE_IDXS_TABLE = {
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
#undef OPLIST
|
||||
|
||||
struct Ins {
|
||||
using IType = std::variant<int64_t, double>;
|
||||
|
||||
constexpr static uint16_t ACCUMULATOR = -1;
|
||||
constexpr static size_t MAX_CALL_SHORT_ARGS = 2;
|
||||
constexpr static size_t MAX_CALL_ARGS = 4;
|
||||
constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15;
|
||||
constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255;
|
||||
|
||||
Opcode opcode = Opcode::INVALID; /* operation type */
|
||||
std::vector<uint16_t> regs; /* list of arguments - registers */
|
||||
std::vector<std::string> ids; /* list of arguments - identifiers */
|
||||
std::vector<IType> imms; /* list of arguments - immediates */
|
||||
std::string label; /* label at the beginning of a line */
|
||||
bool set_label = false; /* whether this label is defined */
|
||||
debuginfo::Ins ins_debug;
|
||||
|
||||
std::string ToString(std::string endline = "", bool print_args = false, size_t first_arg_idx = 0) const;
|
||||
|
||||
bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
|
||||
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
|
||||
const std::unordered_map<std::string_view, panda::Label> &labels) const;
|
||||
|
||||
size_t OperandListLength() const
|
||||
{
|
||||
return regs.size() + ids.size() + imms.size();
|
||||
}
|
||||
|
||||
bool HasFlag(InstFlags flag) const
|
||||
{
|
||||
if (opcode == Opcode::INVALID) {
|
||||
return false;
|
||||
}
|
||||
return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0;
|
||||
}
|
||||
|
||||
bool CanThrow() const
|
||||
{
|
||||
return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) ||
|
||||
HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID);
|
||||
}
|
||||
|
||||
bool IsJump() const
|
||||
{
|
||||
return HasFlag(InstFlags::JUMP);
|
||||
}
|
||||
|
||||
bool IsConditionalJump() const
|
||||
{
|
||||
return IsJump() && HasFlag(InstFlags::COND);
|
||||
}
|
||||
|
||||
bool IsCall() const
|
||||
{ // Non-range call
|
||||
return HasFlag(InstFlags::CALL);
|
||||
}
|
||||
|
||||
bool IsBuiltinIdr6() const
|
||||
{
|
||||
return opcode == Opcode::BUILTIN_IDR6;
|
||||
}
|
||||
|
||||
bool IsPseudoCall() const
|
||||
{
|
||||
return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
|
||||
}
|
||||
|
||||
bool IsReturn() const
|
||||
{
|
||||
return HasFlag(InstFlags::RETURN);
|
||||
}
|
||||
|
||||
size_t MaxRegEncodingWidth() const
|
||||
{
|
||||
if (opcode == Opcode::INVALID) {
|
||||
return 0;
|
||||
}
|
||||
return INST_WIDTH_TABLE[static_cast<size_t>(opcode)];
|
||||
}
|
||||
|
||||
std::vector<uint16_t> Uses() const
|
||||
{
|
||||
if (IsPseudoCall()) {
|
||||
return regs;
|
||||
}
|
||||
|
||||
if (opcode == Opcode::INVALID) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto use_idxs = USE_IDXS_TABLE[static_cast<size_t>(opcode)];
|
||||
std::vector<uint16_t> res;
|
||||
for (auto idx : use_idxs) {
|
||||
if (HasFlag(InstFlags::ACC_READ)) {
|
||||
res.push_back(Ins::ACCUMULATOR);
|
||||
}
|
||||
if (idx != INVALID_REG_IDX) {
|
||||
ASSERT(static_cast<size_t>(idx) < regs.size());
|
||||
res.push_back(regs[idx]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::optional<size_t> Def() const
|
||||
{
|
||||
if (opcode == Opcode::INVALID) {
|
||||
return {};
|
||||
}
|
||||
auto def_idx = DEF_IDX_TABLE[static_cast<size_t>(opcode)];
|
||||
if (def_idx != INVALID_REG_IDX) {
|
||||
return regs[def_idx];
|
||||
}
|
||||
if (HasFlag(InstFlags::ACC_WRITE)) {
|
||||
return Ins::ACCUMULATOR;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool IsValidToEmit() const
|
||||
{
|
||||
const auto INVALID_REG_NUM = 1U << MaxRegEncodingWidth();
|
||||
for (auto reg : regs) {
|
||||
if (reg >= INVALID_REG_NUM) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasDebugInfo() const
|
||||
{
|
||||
return ins_debug.line_number != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string OperandsToString(PrintKind print_kind = PrintKind::DEFAULT, bool print_args = false,
|
||||
size_t first_arg_idx = 0) const;
|
||||
std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const;
|
||||
std::string ImmsToString(bool &first) const;
|
||||
std::string IdsToString(bool &first) const;
|
||||
};
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_INS_H_
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_LABEL_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_LABEL_H_
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "assembly-file-location.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Label {
|
||||
std::string name = "";
|
||||
std::optional<FileLocation> file_location;
|
||||
|
||||
Label(std::string s, size_t b_l, size_t b_r, std::string f_c, bool d, size_t l_n)
|
||||
: name(std::move(s)), file_location({f_c, b_l, b_r, l_n, d})
|
||||
{
|
||||
}
|
||||
|
||||
explicit Label(std::string s) : name(std::move(s)) {}
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_LABEL_H_
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_LITERALS_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_LITERALS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
#include "../libpandafile/literal_data_accessor.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct LiteralArray {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
struct Literal {
|
||||
panda_file::LiteralTag tag_;
|
||||
std::variant<uint8_t, uint16_t, uint32_t, uint64_t, float, double, bool, std::string> value_;
|
||||
};
|
||||
|
||||
std::vector<panda::pandasm::LiteralArray::Literal>
|
||||
literals_; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
|
||||
explicit LiteralArray(std::vector<panda::pandasm::LiteralArray::Literal> literals) : literals_(std::move(literals))
|
||||
{
|
||||
}
|
||||
explicit LiteralArray() = default;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_LITERALS_H_
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_METHODHANDLE_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_METHODHANDLE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct MethodHandle {
|
||||
std::string item_name;
|
||||
panda::panda_file::MethodHandleType type;
|
||||
MethodHandle(std::string s, panda::panda_file::MethodHandleType t) : item_name(std::move(s)), type(t) {}
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_METHODHANDLE_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_PARSER_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_PARSER_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "assembly-context.h"
|
||||
#include "assembly-emitter.h"
|
||||
#include "assembly-field.h"
|
||||
#include "assembly-function.h"
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-label.h"
|
||||
#include "assembly-program.h"
|
||||
#include "assembly-record.h"
|
||||
#include "assembly-type.h"
|
||||
#include "define.h"
|
||||
#include "error.h"
|
||||
#include "ide_helpers.h"
|
||||
#include "lexer.h"
|
||||
#include "meta.h"
|
||||
#include "utils/expected.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
using Instructions = std::pair<std::vector<Ins>, Error>;
|
||||
|
||||
using Functions = std::pair<std::unordered_map<std::string, Function>, std::unordered_map<std::string, Record>>;
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
Parser() = default;
|
||||
|
||||
NO_MOVE_SEMANTIC(Parser);
|
||||
NO_COPY_SEMANTIC(Parser);
|
||||
|
||||
~Parser() = default;
|
||||
|
||||
/*
|
||||
* The main function of parsing, which takes a vector of token vectors and a name of the source file.
|
||||
* Returns a program or an error value: Expected<Program, Error>
|
||||
* This function analyzes code containing several functions:
|
||||
* - Each function used must be declared.
|
||||
* - The correct function declaration looks like this: .function ret_type fun_name([param_type aN,]) [<metadata>]
|
||||
* ([data] shows that this 'data' is optional).
|
||||
* - N in function parameters must increase when number of parameters increases
|
||||
* (Possible: a0, a1,..., aN. Impossible: a1, a10, a13).
|
||||
* - Each function has its own label table.
|
||||
*/
|
||||
Expected<Program, Error> Parse(TokenSet &vectors_tokens, const std::string &file_name = "");
|
||||
|
||||
/*
|
||||
* The main function of parsing, which takes a string with source and a name of the source file.
|
||||
* Returns a program or an error value: Expected<Program, Error>
|
||||
*/
|
||||
Expected<Program, Error> Parse(const std::string &source, const std::string &file_name = "");
|
||||
|
||||
/*
|
||||
* Returns a set error
|
||||
*/
|
||||
Error ShowError() const
|
||||
{
|
||||
return err_;
|
||||
}
|
||||
|
||||
ErrorList ShowWarnings() const
|
||||
{
|
||||
return war_;
|
||||
}
|
||||
|
||||
private:
|
||||
panda::pandasm::Program program_;
|
||||
std::unordered_map<std::string, panda::pandasm::Label> *label_table_ = nullptr;
|
||||
Metadata *metadata_ = nullptr;
|
||||
Context context_; /* token iterator */
|
||||
panda::pandasm::Record *curr_record_ = nullptr;
|
||||
panda::pandasm::Function *curr_func_ = nullptr;
|
||||
panda::pandasm::Ins *curr_ins_ = nullptr;
|
||||
panda::pandasm::Field *curr_fld_ = nullptr;
|
||||
size_t line_stric_ = 0;
|
||||
panda::pandasm::Error err_;
|
||||
panda::pandasm::ErrorList war_;
|
||||
bool open_ = false; /* flag of being in a code section */
|
||||
bool record_def_ = false;
|
||||
bool func_def_ = false;
|
||||
|
||||
inline Error GetError(const std::string &mess = "", Error::ErrorType err = Error::ErrorType::ERR_NONE,
|
||||
int8_t shift = 0, int token_shift = 0, const std::string &add_mess = "") const
|
||||
{
|
||||
return Error(mess, line_stric_, err, add_mess,
|
||||
context_.tokens[context_.number + token_shift - 1].bound_left + shift,
|
||||
context_.tokens[context_.number + token_shift - 1].bound_right,
|
||||
context_.tokens[context_.number + token_shift - 1].whole_line);
|
||||
}
|
||||
|
||||
inline void GetWarning(const std::string &mess = "", Error::ErrorType err = Error::ErrorType::ERR_NONE,
|
||||
int8_t shift = 0, const std::string &add_mess = "")
|
||||
{
|
||||
war_.emplace_back(mess, line_stric_, err, add_mess, context_.tokens[context_.number - 1].bound_left + shift,
|
||||
context_.tokens[context_.number - 1].bound_right,
|
||||
context_.tokens[context_.number - 1].whole_line, Error::ErrorClass::WARNING);
|
||||
}
|
||||
|
||||
SourcePosition GetCurrentPosition(bool left_bound) const
|
||||
{
|
||||
if (left_bound) {
|
||||
return SourcePosition {line_stric_, context_.tokens[context_.number - 1].bound_left};
|
||||
}
|
||||
return SourcePosition {line_stric_, context_.tokens[context_.number - 1].bound_right};
|
||||
}
|
||||
|
||||
bool LabelValidName();
|
||||
bool TypeValidName();
|
||||
bool RegValidName();
|
||||
bool ParamValidName();
|
||||
bool FunctionValidName();
|
||||
bool ParseFunctionName();
|
||||
bool ParseLabel();
|
||||
bool ParseOperation();
|
||||
bool ParseOperands();
|
||||
bool ParseFunctionCode();
|
||||
bool ParseFunctionInstruction();
|
||||
bool ParseFunctionFullSign();
|
||||
bool ParseFunctionReturn();
|
||||
bool ParseFunctionArg();
|
||||
bool ParseFunctionArgComma(bool &comma);
|
||||
bool ParseFunctionArgs();
|
||||
bool ParseType(Type *type);
|
||||
bool PrefixedValidName();
|
||||
bool ParseMetaListComma(bool &comma, bool eq);
|
||||
bool MeetExpMetaList(bool eq);
|
||||
bool BuildMetaListAttr(bool &eq, std::string &attribute_name, std::string &attribute_value);
|
||||
bool ParseMetaList(bool flag);
|
||||
bool ParseMetaDef();
|
||||
bool ParseRecordFullSign();
|
||||
bool ParseRecordFields();
|
||||
bool ParseRecordField();
|
||||
bool ParseRecordName();
|
||||
bool RecordValidName();
|
||||
bool ParseFieldName();
|
||||
bool ParseFieldType();
|
||||
std::optional<std::string> ParseStringLiteral();
|
||||
int64_t MnemonicToBuiltinId();
|
||||
|
||||
bool ParseOperandVreg();
|
||||
bool ParseOperandComma();
|
||||
bool ParseOperandInteger();
|
||||
bool ParseOperandFloat();
|
||||
bool ParseOperandId();
|
||||
bool ParseOperandLabel();
|
||||
bool ParseOperandField();
|
||||
bool ParseOperandType(Type::VerificationType ver_type);
|
||||
bool ParseOperandNone();
|
||||
bool ParseOperandString();
|
||||
bool ParseOperandCall();
|
||||
bool ParseOperandBuiltinMnemonic();
|
||||
|
||||
void SetFunctionInformation();
|
||||
void SetRecordInformation();
|
||||
void SetOperationInformation();
|
||||
void ParseAsCatchall(const std::vector<Token> &tokens);
|
||||
void ParseAsLanguage(const std::vector<Token> &tokens, bool &is_lang_parsed, bool &is_first_statement);
|
||||
void ParseAsRecord(const std::vector<Token> &tokens);
|
||||
void ParseAsFunction(const std::vector<Token> &tokens);
|
||||
void ParseAsBraceRight(const std::vector<Token> &tokens);
|
||||
bool ParseAfterLine(bool &is_first_statement);
|
||||
Expected<Program, Error> ParseAfterMainLoop(const std::string &file_name);
|
||||
void ParseResetFunctionLabelsAndParams();
|
||||
void ParseResetTables();
|
||||
void ParseResetFunctionTable();
|
||||
void ParseResetRecordTable();
|
||||
void ParseAsLanguageDirective();
|
||||
Function::CatchBlock PrepareCatchBlock(bool is_catchall, size_t size, size_t catchall_tokens_num,
|
||||
size_t catch_tokens_num);
|
||||
void ParseAsCatchDirective();
|
||||
void SetError();
|
||||
void SetMetadataContextError(const Metadata::Error &err, bool has_value);
|
||||
|
||||
Expected<char, Error> ParseOctalEscapeSequence(std::string_view s, size_t *i);
|
||||
Expected<char, Error> ParseHexEscapeSequence(std::string_view s, size_t *i);
|
||||
Expected<char, Error> ParseEscapeSequence(std::string_view s, size_t *i);
|
||||
|
||||
template <class T>
|
||||
auto TryEmplaceInTable(bool flag, T &item)
|
||||
{
|
||||
return item.try_emplace(std::string(context_.GiveToken().data(), context_.GiveToken().length()),
|
||||
std::string(context_.GiveToken().data(), context_.GiveToken().length()), program_.lang,
|
||||
context_.tokens[context_.number - 1].bound_left,
|
||||
context_.tokens[context_.number - 1].bound_right,
|
||||
context_.tokens[context_.number - 1].whole_line, flag, line_stric_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool AddObjectInTable(bool flag, T &item)
|
||||
{
|
||||
auto [iter, is_inserted] = TryEmplaceInTable(flag, item);
|
||||
|
||||
if (is_inserted) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (iter->second.file_location->is_defined && flag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!iter->second.file_location->is_defined && flag) {
|
||||
iter->second.file_location->is_defined = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!iter->second.file_location->is_defined) {
|
||||
iter->second.file_location->bound_left = context_.tokens[context_.number - 1].bound_left;
|
||||
iter->second.file_location->bound_right = context_.tokens[context_.number - 1].bound_right;
|
||||
iter->second.file_location->whole_line = context_.tokens[context_.number - 1].whole_line;
|
||||
iter->second.file_location->line_number = line_stric_;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
inline auto Parser::TryEmplaceInTable(bool flag, std::unordered_map<std::string, panda::pandasm::Label> &item)
|
||||
{
|
||||
return item.try_emplace(std::string(context_.GiveToken().data(), context_.GiveToken().length()),
|
||||
std::string(context_.GiveToken().data(), context_.GiveToken().length()),
|
||||
context_.tokens[context_.number - 1].bound_left,
|
||||
context_.tokens[context_.number - 1].bound_right,
|
||||
context_.tokens[context_.number - 1].whole_line, flag, line_stric_);
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_PARSER_H_
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 "assembly-program.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "ide_helpers.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::string Program::JsonDump() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{ \"functions\": ";
|
||||
ss << JsonSerializeProgramItems(function_table);
|
||||
ss << ", \"records\": ";
|
||||
ss << JsonSerializeProgramItems(record_table);
|
||||
ss << " }";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -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 PANDA_ASSEMBLER_ASSEMBLY_PROGRAM_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_PROGRAM_H_
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "assembly-function.h"
|
||||
#include "assembly-record.h"
|
||||
#include "assembly-type.h"
|
||||
#include "assembly-methodhandle.h"
|
||||
#include "assembly-literals.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Program {
|
||||
extensions::Language lang {extensions::Language::PANDA_ASSEMBLY};
|
||||
std::unordered_map<std::string, panda::pandasm::Record> record_table;
|
||||
std::unordered_map<std::string, panda::pandasm::Function> function_table;
|
||||
std::map<std::string, panda::pandasm::LiteralArray> literalarray_table;
|
||||
std::unordered_set<std::string> strings;
|
||||
std::unordered_set<Type> array_types;
|
||||
|
||||
/*
|
||||
* Returns a JSON string with the program structure and scopes locations
|
||||
*/
|
||||
std::string JsonDump() const;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_PROGRAM_H_
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_RECORD_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_RECORD_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-field.h"
|
||||
#include "assembly-file-location.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "ide_helpers.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Record {
|
||||
std::string name = "";
|
||||
bool conflict = false; /* Name conflicts with panda primitive types. Need special handle. */
|
||||
extensions::Language language;
|
||||
std::unique_ptr<RecordMetadata> metadata;
|
||||
std::vector<Field> field_list; /* class fields list */
|
||||
size_t params_num = 0;
|
||||
bool body_presence = false;
|
||||
SourceLocation body_location;
|
||||
std::string source_file; /* The file in which the record is defined or empty */
|
||||
std::optional<FileLocation> file_location;
|
||||
|
||||
Record(std::string s, extensions::Language lang, size_t b_l, size_t b_r, std::string f_c, bool d, size_t l_n)
|
||||
: name(std::move(s)),
|
||||
language(lang),
|
||||
metadata(extensions::MetadataExtension::CreateRecordMetadata(lang)),
|
||||
file_location({f_c, b_l, b_r, l_n, d})
|
||||
{
|
||||
}
|
||||
|
||||
Record(std::string s, extensions::Language lang)
|
||||
: name(std::move(s)), language(lang), metadata(extensions::MetadataExtension::CreateRecordMetadata(lang))
|
||||
{
|
||||
}
|
||||
|
||||
bool HasImplementation() const
|
||||
{
|
||||
return !metadata->IsForeign();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_RECORD_H_
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 <unordered_map>
|
||||
|
||||
#include "assembly-type.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
static std::unordered_map<std::string_view, std::string_view> primitive_types = {
|
||||
{"u1", "Z"}, {"i8", "B"}, {"u8", "H"}, {"i16", "S"}, {"u16", "C"}, {"i32", "I"}, {"u32", "U"},
|
||||
{"f32", "F"}, {"f64", "D"}, {"i64", "J"}, {"u64", "Q"}, {"void", "V"}, {"any", "A"}};
|
||||
|
||||
std::string Type::GetDescriptor(bool ignore_primitive) const
|
||||
{
|
||||
if (!ignore_primitive) {
|
||||
auto it = primitive_types.find(component_name_);
|
||||
if (it != primitive_types.cend()) {
|
||||
return std::string(rank_, '[') + it->second.data();
|
||||
}
|
||||
}
|
||||
|
||||
std::string res = std::string(rank_, '[') + "L" + component_name_ + ";";
|
||||
std::replace(res.begin(), res.end(), '.', '/');
|
||||
return res;
|
||||
}
|
||||
|
||||
/* static */
|
||||
panda_file::Type::TypeId Type::GetId(std::string_view name, bool ignore_primitive)
|
||||
{
|
||||
static std::unordered_map<std::string_view, panda_file::Type::TypeId> panda_types = {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define PANDATYPE(name, inst_code) {std::string_view(name), panda_file::Type::TypeId::inst_code},
|
||||
PANDA_ASSEMBLER_TYPES(PANDATYPE)
|
||||
#undef PANDATYPE
|
||||
};
|
||||
|
||||
if (!ignore_primitive) {
|
||||
auto iter = panda_types.find(name);
|
||||
if (iter == panda_types.end()) {
|
||||
return panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
return panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::string Type::GetName(std::string_view component_name, size_t rank)
|
||||
{
|
||||
std::string name(component_name);
|
||||
while (rank-- > 0) {
|
||||
name += "[]";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/* static */
|
||||
Type Type::FromDescriptor(std::string_view descriptor)
|
||||
{
|
||||
static std::unordered_map<std::string_view, std::string_view> reverse_primitive_types = {
|
||||
{"Z", "u1"}, {"B", "i8"}, {"H", "u8"}, {"S", "i16"}, {"C", "u16"}, {"I", "i32"}, {"U", "u32"},
|
||||
{"F", "f32"}, {"D", "f64"}, {"J", "i64"}, {"Q", "u64"}, {"V", "void"}, {"A", "any"}};
|
||||
|
||||
size_t i = 0;
|
||||
while (descriptor[i] == '[') {
|
||||
++i;
|
||||
}
|
||||
|
||||
size_t rank = i;
|
||||
bool is_ref_type = descriptor[i] == 'L';
|
||||
if (is_ref_type) {
|
||||
descriptor.remove_suffix(1); /* Remove semicolon */
|
||||
++i;
|
||||
}
|
||||
|
||||
descriptor.remove_prefix(i);
|
||||
|
||||
if (is_ref_type) {
|
||||
return Type(descriptor, rank);
|
||||
}
|
||||
return Type(reverse_primitive_types[descriptor], rank);
|
||||
}
|
||||
|
||||
/* static */
|
||||
Type Type::FromName(std::string_view name, bool ignore_primitive)
|
||||
{
|
||||
constexpr size_t STEP = 2;
|
||||
|
||||
size_t size = name.size();
|
||||
size_t i = 0;
|
||||
|
||||
while (name[size - i - 1] == ']') {
|
||||
i += STEP;
|
||||
}
|
||||
|
||||
name.remove_suffix(i);
|
||||
return Type(name, i / STEP, ignore_primitive);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool Type::IsPandaPrimitiveType(const std::string &name)
|
||||
{
|
||||
auto it = primitive_types.find(name);
|
||||
if (it != primitive_types.cend()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_ASSEMBLY_TYPE_H_
|
||||
#define PANDA_ASSEMBLER_ASSEMBLY_TYPE_H_
|
||||
|
||||
#include "define.h"
|
||||
#include "file_items.h"
|
||||
#include "isa.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class Type {
|
||||
public:
|
||||
enum VerificationType {
|
||||
TYPE_ID_OBJECT,
|
||||
TYPE_ID_ARRAY,
|
||||
TYPE_ID_ANY_OBJECT,
|
||||
};
|
||||
|
||||
Type() = default;
|
||||
DEFAULT_MOVE_SEMANTIC(Type);
|
||||
DEFAULT_COPY_SEMANTIC(Type);
|
||||
~Type() = default;
|
||||
|
||||
Type(std::string_view component_name, size_t rank, bool ignore_primitive = false)
|
||||
: component_name_(component_name), rank_(rank)
|
||||
{
|
||||
name_ = GetName(component_name_, rank_);
|
||||
type_id_ = GetId(name_, ignore_primitive);
|
||||
}
|
||||
|
||||
Type(const Type &component_type, size_t rank)
|
||||
: Type(component_type.GetComponentName(), component_type.GetRank() + rank)
|
||||
{
|
||||
}
|
||||
|
||||
std::string GetDescriptor(bool ignore_primitive = false) const;
|
||||
|
||||
std::string GetName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string GetComponentName() const
|
||||
{
|
||||
return component_name_;
|
||||
}
|
||||
|
||||
size_t GetRank() const
|
||||
{
|
||||
return rank_;
|
||||
}
|
||||
|
||||
Type GetComponentType() const
|
||||
{
|
||||
return Type(component_name_, rank_ > 0 ? rank_ - 1 : 0);
|
||||
}
|
||||
|
||||
panda_file::Type::TypeId GetId() const
|
||||
{
|
||||
return type_id_;
|
||||
}
|
||||
|
||||
bool IsArrayContainsPrimTypes() const
|
||||
{
|
||||
auto elem = GetId(component_name_);
|
||||
return elem != panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return !component_name_.empty();
|
||||
}
|
||||
|
||||
bool IsArray() const
|
||||
{
|
||||
return rank_ > 0;
|
||||
}
|
||||
|
||||
bool IsObject() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
|
||||
bool IsTagged() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::TAGGED;
|
||||
}
|
||||
|
||||
bool IsIntegral() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::U1 || type_id_ == panda_file::Type::TypeId::U8 ||
|
||||
type_id_ == panda_file::Type::TypeId::I8 || type_id_ == panda_file::Type::TypeId::U16 ||
|
||||
type_id_ == panda_file::Type::TypeId::I16 || type_id_ == panda_file::Type::TypeId::U32 ||
|
||||
type_id_ == panda_file::Type::TypeId::I32 || type_id_ == panda_file::Type::TypeId::U64 ||
|
||||
type_id_ == panda_file::Type::TypeId::I64;
|
||||
}
|
||||
|
||||
bool FitsInto32() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::U1 || type_id_ == panda_file::Type::TypeId::U8 ||
|
||||
type_id_ == panda_file::Type::TypeId::I8 || type_id_ == panda_file::Type::TypeId::U16 ||
|
||||
type_id_ == panda_file::Type::TypeId::I16 || type_id_ == panda_file::Type::TypeId::U32 ||
|
||||
type_id_ == panda_file::Type::TypeId::I32;
|
||||
}
|
||||
|
||||
bool IsFloat32() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::F32;
|
||||
}
|
||||
|
||||
bool IsFloat64() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::F64;
|
||||
}
|
||||
|
||||
bool IsPrim32() const
|
||||
{
|
||||
return (IsIntegral() && FitsInto32()) || IsFloat32();
|
||||
}
|
||||
|
||||
bool IsPrim64() const
|
||||
{
|
||||
return (IsIntegral() && !FitsInto32()) || IsFloat64();
|
||||
}
|
||||
|
||||
bool IsPrimitive() const
|
||||
{
|
||||
return IsPrim64() || IsPrim32();
|
||||
}
|
||||
|
||||
bool IsVoid() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::VOID;
|
||||
}
|
||||
|
||||
static panda_file::Type::TypeId GetId(std::string_view name, bool ignore_primitive = false);
|
||||
|
||||
bool operator==(const Type &type) const
|
||||
{
|
||||
return name_ == type.name_;
|
||||
}
|
||||
|
||||
static Type FromDescriptor(std::string_view descriptor);
|
||||
|
||||
static Type FromName(std::string_view name, bool ignore_primitive = false);
|
||||
|
||||
static bool IsPandaPrimitiveType(const std::string &name);
|
||||
|
||||
private:
|
||||
static std::string GetName(std::string_view component_name, size_t rank);
|
||||
|
||||
std::string component_name_;
|
||||
size_t rank_ {0};
|
||||
std::string name_;
|
||||
panda_file::Type::TypeId type_id_ {panda_file::Type::TypeId::VOID};
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
class hash<panda::pandasm::Type> {
|
||||
public:
|
||||
size_t operator()(const panda::pandasm::Type &type) const
|
||||
{
|
||||
return std::hash<std::string>()(type.GetName());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ASSEMBLY_TYPE_H_
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 <string_view>
|
||||
#include "assembly-parser.h"
|
||||
#include "utils/number-utils.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
void Context::Make(const std::vector<panda::pandasm::Token> &t)
|
||||
{
|
||||
err = {};
|
||||
ins_number = 0;
|
||||
tokens = t;
|
||||
number = 1;
|
||||
end = false;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
|
||||
id = this->tokens[number - 1].type;
|
||||
}
|
||||
|
||||
size_t Context::Len() const
|
||||
{
|
||||
return token.size();
|
||||
}
|
||||
|
||||
bool Context::ValidateRegisterName(char c, size_t n) const
|
||||
{
|
||||
if (token[0] == c) {
|
||||
std::string_view p = token;
|
||||
p.remove_prefix(1);
|
||||
if (p.empty() || (p.size() > 1 && p[0] == '0')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c != 'a') {
|
||||
for (const auto &ch : p) {
|
||||
if (std::isdigit(ch) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ToNumber(p) > n) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Context::ValidateParameterName(size_t number_of_params_already_is) const
|
||||
{
|
||||
if (number_of_params_already_is >= MAX_DWORD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (token[0] == 'a') {
|
||||
std::string_view p = token;
|
||||
p.remove_prefix(1);
|
||||
if (ToNumber(p) == number_of_params_already_is) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string_view Context::GiveToken()
|
||||
{
|
||||
return token;
|
||||
}
|
||||
|
||||
Token::Type Context::Next()
|
||||
{
|
||||
if (this->tokens.size() > number) {
|
||||
return this->tokens[number].type;
|
||||
}
|
||||
|
||||
return this->tokens[number - 1].type;
|
||||
}
|
||||
|
||||
void Context::UpSignOperation()
|
||||
{
|
||||
signop = id;
|
||||
}
|
||||
|
||||
Token::Type Context::WaitFor()
|
||||
{
|
||||
return signop;
|
||||
}
|
||||
|
||||
bool Context::Mask()
|
||||
{
|
||||
return end;
|
||||
}
|
||||
|
||||
bool Context::NextMask()
|
||||
{
|
||||
if (end) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->tokens.size() < number + 1;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cert-dcl21-cpp)
|
||||
Token::Type Context::operator++(int)
|
||||
{
|
||||
Token::Type last_id = id;
|
||||
|
||||
if (this->tokens.size() > number) {
|
||||
++number;
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = true;
|
||||
}
|
||||
|
||||
return last_id;
|
||||
}
|
||||
|
||||
Token::Type Context::operator++()
|
||||
{
|
||||
if (this->tokens.size() > number) {
|
||||
++number;
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = true;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cert-dcl21-cpp)
|
||||
Token::Type Context::operator--(int)
|
||||
{
|
||||
Token::Type last_id = id;
|
||||
|
||||
if (number > 1) {
|
||||
end = false;
|
||||
--number;
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = false;
|
||||
}
|
||||
|
||||
return last_id;
|
||||
}
|
||||
|
||||
Token::Type Context::operator--()
|
||||
{
|
||||
if (number > 1) {
|
||||
end = false;
|
||||
--number;
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = false;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
Token::Type Context::operator*()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -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 PANDA_ASSEMBLER_DEFINE_H_
|
||||
#define PANDA_ASSEMBLER_DEFINE_H_
|
||||
|
||||
/* Implementation-specific definitions */
|
||||
|
||||
constexpr char PARSE_COMMENT_MARKER = '#';
|
||||
|
||||
constexpr char PARSE_AREA_MARKER = '.';
|
||||
|
||||
#define PANDA_ASSEMBLER_TYPES(_) \
|
||||
_("void", VOID) \
|
||||
_("u1", U1) \
|
||||
_("u8", U8) \
|
||||
_("i8", I8) \
|
||||
_("u16", U16) \
|
||||
_("i16", I16) \
|
||||
_("u32", U32) \
|
||||
_("i32", I32) \
|
||||
_("u64", U64) \
|
||||
_("i64", I64) \
|
||||
_("f32", F32) \
|
||||
_("f64", F64) \
|
||||
_("any", TAGGED)
|
||||
|
||||
#define KEYWORDS_LIST(_) \
|
||||
_(".catch", CATCH) \
|
||||
_(".catchall", CATCHALL) \
|
||||
_(".language", LANG) \
|
||||
_(".function", FUN) \
|
||||
_(".record", REC) \
|
||||
_(".field", FLD)
|
||||
|
||||
#endif // PANDA_ASSEMBLER_DEFINE_H_
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_ASSEMBLER_ERROR_H_
|
||||
#define PANDA_ASSEMBLER_ERROR_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "define.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Error {
|
||||
enum class ErrorClass { WARNING = 0, ERROR };
|
||||
enum class ErrorType {
|
||||
ERR_NONE = 0,
|
||||
|
||||
// Lexer
|
||||
ERR_STRING_MISSING_TERMINATING_CHARACTER,
|
||||
|
||||
// Parser
|
||||
ERR_BAD_LABEL,
|
||||
ERR_BAD_LABEL_EXT,
|
||||
ERR_BAD_NAME_ID,
|
||||
ERR_BAD_NAME_REG,
|
||||
ERR_BAD_INTEGER_NAME,
|
||||
ERR_BAD_INTEGER_WIDTH,
|
||||
ERR_BAD_FLOAT_NAME,
|
||||
ERR_BAD_FLOAT_WIDTH,
|
||||
ERR_BAD_NUMBER_OPERANDS,
|
||||
ERR_BAD_OPERAND,
|
||||
ERR_BAD_OPERATION_NAME,
|
||||
ERR_BAD_NONEXISTING_OPERATION,
|
||||
ERR_BAD_ID_FUNCTION,
|
||||
ERR_BAD_ID_RECORD,
|
||||
ERR_BAD_ID_FIELD,
|
||||
ERR_BAD_FUNCTION_NAME,
|
||||
ERR_BAD_RECORD_NAME,
|
||||
ERR_BAD_DEFINITION_METADATA,
|
||||
ERR_BAD_DEFINITION_FUNCTION,
|
||||
ERR_BAD_DEFINITION_RECORD,
|
||||
ERR_BAD_METADATA_BOUND,
|
||||
ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE,
|
||||
ERR_BAD_METADATA_INVALID_VALUE,
|
||||
ERR_BAD_METADATA_MISSING_ATTRIBUTE,
|
||||
ERR_BAD_METADATA_MISSING_VALUE,
|
||||
ERR_BAD_METADATA_UNEXPECTED_ATTRIBUTE,
|
||||
ERR_BAD_METADATA_UNEXPECTED_VALUE,
|
||||
ERR_BAD_METADATA_MULTIPLE_ATTRIBUTE,
|
||||
ERR_BAD_FUNCTION_PARAMETERS,
|
||||
ERR_BAD_FUNCTION_RETURN_VALUE,
|
||||
ERR_FUNCTION_ARGUMENT_MISMATCH,
|
||||
ERR_BAD_FIELD_MISSING_NAME,
|
||||
ERR_BAD_FIELD_VALUE_TYPE,
|
||||
ERR_BAD_CHARACTER,
|
||||
ERR_BAD_KEYWORD,
|
||||
ERR_BAD_DEFINITION,
|
||||
ERR_BAD_BOUND,
|
||||
ERR_BAD_END,
|
||||
ERR_BAD_CLOSE,
|
||||
ERR_BAD_ARGS_BOUND,
|
||||
ERR_BAD_TYPE,
|
||||
ERR_BAD_PARAM_NAME,
|
||||
ERR_BAD_NOEXP_DELIM,
|
||||
ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE,
|
||||
ERR_BAD_STRING_UNKNOWN_ESCAPE_SEQUENCE,
|
||||
ERR_BAD_ARRAY_TYPE_BOUND,
|
||||
ERR_UNDEFINED_TYPE,
|
||||
ERR_MULTIPLE_DIRECTIVES,
|
||||
ERR_INCORRECT_DIRECTIVE_LOCATION,
|
||||
ERR_BAD_DIRECTIVE_DECLARATION,
|
||||
ERR_UNKNOWN_LANGUAGE,
|
||||
ERR_BAD_MNEMONIC_NAME,
|
||||
ERR_REPEATING_FIELD_NAME,
|
||||
|
||||
// Warnings
|
||||
WAR_UNEXPECTED_RETURN_TYPE,
|
||||
WAR_UNEXPECTED_TYPE_ID,
|
||||
};
|
||||
|
||||
ErrorClass type;
|
||||
std::string whole_line;
|
||||
size_t pos; // position to highlight the word
|
||||
size_t end;
|
||||
ErrorType err;
|
||||
std::string message;
|
||||
std::string verbose;
|
||||
size_t line_number;
|
||||
|
||||
inline Error() : Error("No messages", 0, ErrorType::ERR_NONE, "", 0, 0, "") {}
|
||||
|
||||
inline Error(std::string s, size_t line, ErrorType error_type, std::string overinfo, size_t p, size_t e,
|
||||
std::string buff, ErrorClass class_type = ErrorClass::ERROR)
|
||||
: type(class_type),
|
||||
whole_line(std::move(buff)),
|
||||
pos(p),
|
||||
end(e),
|
||||
err(error_type),
|
||||
message(std::move(s)),
|
||||
verbose(std::move(overinfo)),
|
||||
line_number(line)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using ErrorList = std::vector<Error>;
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ERROR_H_
|
||||
@@ -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_meta.h"
|
||||
|
||||
namespace panda::pandasm::extensions::ecmascript {
|
||||
|
||||
#include <ecmascript_meta_gen.h>
|
||||
|
||||
} // namespace panda::pandasm::extensions::ecmascript
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_EXTENSIONS_ECMASCRIPT_ECMASCRIPT_META_H_
|
||||
#define PANDA_ASSEMBLER_EXTENSIONS_ECMASCRIPT_ECMASCRIPT_META_H_
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace panda::pandasm::extensions::ecmascript {
|
||||
|
||||
class RecordMetadata : public pandasm::RecordMetadata {
|
||||
public:
|
||||
std::string GetBase() const override
|
||||
{
|
||||
auto base = GetAttributeValue("ecmascript.extends");
|
||||
if (base) {
|
||||
return base.value();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> GetInterfaces() const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool IsAnnotation() const override
|
||||
{
|
||||
return (GetAccessFlags() & ACC_ANNOTATION) != 0;
|
||||
}
|
||||
|
||||
bool IsRuntimeAnnotation() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
class FieldMetadata : public pandasm::FieldMetadata {
|
||||
protected:
|
||||
bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
class FunctionMetadata : public pandasm::FunctionMetadata {
|
||||
protected:
|
||||
bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
class ParamMetadata : public pandasm::ParamMetadata {
|
||||
protected:
|
||||
bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm::extensions::ecmascript
|
||||
|
||||
#endif // PANDA_ASSEMBLER_EXTENSIONS_ECMASCRIPT_ECMASCRIPT_META_H_
|
||||
@@ -0,0 +1,27 @@
|
||||
# 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.
|
||||
|
||||
language: EcmaScript
|
||||
|
||||
attributes:
|
||||
- name: annotation
|
||||
type: bool
|
||||
flags: [ACC_ANNOTATION]
|
||||
applicable_to:
|
||||
- record
|
||||
|
||||
- name: extends
|
||||
type: record
|
||||
multiple: false
|
||||
applicable_to:
|
||||
- record
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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 "extensions.h"
|
||||
#include "ecmascript/ecmascript_meta.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::pandasm::extensions {
|
||||
|
||||
std::optional<Language> LanguageFromString(std::string_view lang)
|
||||
{
|
||||
if (lang == "ECMAScript") {
|
||||
return Language::ECMASCRIPT;
|
||||
}
|
||||
|
||||
if (lang == "PandaAssembly") {
|
||||
return Language::PANDA_ASSEMBLY;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string LanguageToString(const Language &lang)
|
||||
{
|
||||
if (lang == Language::ECMASCRIPT) {
|
||||
return "ECMAScript";
|
||||
}
|
||||
|
||||
if (lang == Language::PANDA_ASSEMBLY) {
|
||||
return "PandaAssembly";
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string GetCtorName(Language lang)
|
||||
{
|
||||
switch (lang) {
|
||||
case Language::ECMASCRIPT:
|
||||
return ".ctor";
|
||||
case Language::PANDA_ASSEMBLY:
|
||||
return ".ctor";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string GetCctorName(Language lang)
|
||||
{
|
||||
switch (lang) {
|
||||
case Language::ECMASCRIPT:
|
||||
return ".cctor";
|
||||
case Language::PANDA_ASSEMBLY:
|
||||
return ".cctor";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::unique_ptr<RecordMetadata> MetadataExtension::CreateRecordMetadata(Language lang)
|
||||
{
|
||||
switch (lang) {
|
||||
case Language::ECMASCRIPT:
|
||||
return std::make_unique<ecmascript::RecordMetadata>();
|
||||
case Language::PANDA_ASSEMBLY:
|
||||
return std::make_unique<RecordMetadata>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::unique_ptr<FieldMetadata> MetadataExtension::CreateFieldMetadata(Language lang)
|
||||
{
|
||||
switch (lang) {
|
||||
case Language::ECMASCRIPT:
|
||||
return std::make_unique<FieldMetadata>();
|
||||
case Language::PANDA_ASSEMBLY:
|
||||
return std::make_unique<FieldMetadata>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::unique_ptr<FunctionMetadata> MetadataExtension::CreateFunctionMetadata(Language lang)
|
||||
{
|
||||
switch (lang) {
|
||||
case Language::ECMASCRIPT:
|
||||
return std::make_unique<FunctionMetadata>();
|
||||
case Language::PANDA_ASSEMBLY:
|
||||
return std::make_unique<FunctionMetadata>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::unique_ptr<ParamMetadata> MetadataExtension::CreateParamMetadata(Language lang)
|
||||
{
|
||||
switch (lang) {
|
||||
case Language::ECMASCRIPT:
|
||||
return std::make_unique<ParamMetadata>();
|
||||
case Language::PANDA_ASSEMBLY:
|
||||
return std::make_unique<ParamMetadata>();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm::extensions
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_EXTENSIONS_EXTENSIONS_H_
|
||||
#define PANDA_ASSEMBLER_EXTENSIONS_EXTENSIONS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
namespace panda::pandasm::extensions {
|
||||
|
||||
enum class Language { ECMASCRIPT, PANDA_ASSEMBLY };
|
||||
|
||||
std::optional<Language> LanguageFromString(std::string_view lang);
|
||||
|
||||
std::string LanguageToString(const Language &lang);
|
||||
|
||||
std::string GetCtorName(Language lang);
|
||||
|
||||
std::string GetCctorName(Language lang);
|
||||
|
||||
class MetadataExtension {
|
||||
public:
|
||||
static std::unique_ptr<RecordMetadata> CreateRecordMetadata(Language lang);
|
||||
|
||||
static std::unique_ptr<FieldMetadata> CreateFieldMetadata(Language lang);
|
||||
|
||||
static std::unique_ptr<FunctionMetadata> CreateFunctionMetadata(Language lang);
|
||||
|
||||
static std::unique_ptr<ParamMetadata> CreateParamMetadata(Language lang);
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm::extensions
|
||||
|
||||
#endif // PANDA_ASSEMBLER_EXTENSIONS_EXTENSIONS_H_
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_IDE_HELPERS_H_
|
||||
#define PANDA_ASSEMBLER_IDE_HELPERS_H_
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct SourcePosition {
|
||||
size_t line = 0;
|
||||
size_t column = 0;
|
||||
|
||||
std::string JsonSerialize() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{ "
|
||||
<< "\"line\": " << line << ", "
|
||||
<< "\"column\": " << column << " }";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct SourceLocation {
|
||||
SourcePosition begin;
|
||||
SourcePosition end;
|
||||
|
||||
std::string JsonSerialize() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{ "
|
||||
<< "\"begin\": " << begin.JsonSerialize() << ", "
|
||||
<< "\"end\": " << end.JsonSerialize() << " }";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::string JsonSerializeItemBody(const T &item)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::string quoted_name = "\"" + item.name + "\"";
|
||||
ss << "{ "
|
||||
<< "\"name\": " << quoted_name;
|
||||
if (item.file_location->is_defined) {
|
||||
ss << ", "
|
||||
<< "\"bodyLocation\": " << item.body_location.JsonSerialize() << " }";
|
||||
} else {
|
||||
ss << " }";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string JsonSerializeProgramItems(const T &item_table)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "[ ";
|
||||
auto it = item_table.begin();
|
||||
if (it != item_table.end()) {
|
||||
ss << JsonSerializeItemBody(it->second);
|
||||
++it;
|
||||
}
|
||||
while (it != item_table.end()) {
|
||||
ss << ", " << JsonSerializeItemBody(it->second);
|
||||
++it;
|
||||
}
|
||||
ss << " ]";
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_IDE_HELPERS_H_
|
||||
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* 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 "lexer.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
Token::Type FindDelim(char c)
|
||||
{
|
||||
// The map of delimiters
|
||||
static const std::unordered_map<char, Token::Type> DELIM = {{',', Token::Type::DEL_COMMA},
|
||||
{':', Token::Type::DEL_COLON},
|
||||
{'{', Token::Type::DEL_BRACE_L},
|
||||
{'}', Token::Type::DEL_BRACE_R},
|
||||
{'(', Token::Type::DEL_BRACKET_L},
|
||||
{')', Token::Type::DEL_BRACKET_R},
|
||||
{'<', Token::Type::DEL_LT},
|
||||
{'>', Token::Type::DEL_GT},
|
||||
{'=', Token::Type::DEL_EQ},
|
||||
{'[', Token::Type::DEL_SQUARE_BRACKET_L},
|
||||
{']', Token::Type::DEL_SQUARE_BRACKET_R}};
|
||||
|
||||
auto iter = DELIM.find(c);
|
||||
if (iter == DELIM.end()) {
|
||||
return Token::Type::ID_BAD;
|
||||
}
|
||||
|
||||
return DELIM.at(c);
|
||||
}
|
||||
|
||||
Token::Type FindOperation(std::string_view s)
|
||||
{
|
||||
// Generate the map of OPERATIONS from ISA
|
||||
static const std::unordered_map<std::string_view, Token::Type> OPERATIONS = {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(inst_code, name, optype, width, flags, dst_idx, use_idxs) \
|
||||
{std::string_view(name), Token::Type::ID_OP_##inst_code},
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)
|
||||
#undef OPLIST
|
||||
};
|
||||
|
||||
auto iter = OPERATIONS.find(s);
|
||||
if (iter == OPERATIONS.end()) {
|
||||
return Token::Type::ID_BAD;
|
||||
}
|
||||
|
||||
return OPERATIONS.at(s);
|
||||
}
|
||||
|
||||
Token::Type Findkeyword(std::string_view s)
|
||||
{
|
||||
// Generate the map of KEYWORDS
|
||||
static const std::unordered_map<std::string_view, Token::Type> KEYWORDS = {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define KEYWORDS(name, inst_code) {std::string_view(name), Token::Type::ID_##inst_code},
|
||||
KEYWORDS_LIST(KEYWORDS)
|
||||
#undef KEYWORDS
|
||||
};
|
||||
|
||||
auto iter = KEYWORDS.find(s);
|
||||
if (iter == KEYWORDS.end()) {
|
||||
return Token::Type::ID_BAD;
|
||||
}
|
||||
|
||||
return KEYWORDS.at(s);
|
||||
}
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
||||
std::string_view TokenTypeWhat(Token::Type t)
|
||||
{
|
||||
if (t >= Token::Type::OPERATION && t < Token::Type::KEYWORD) {
|
||||
return "OPERATION";
|
||||
}
|
||||
|
||||
if (t >= Token::Type::KEYWORD) {
|
||||
return "KEYWORD";
|
||||
}
|
||||
|
||||
switch (t) {
|
||||
case Token::Type::ID_BAD: {
|
||||
return "ID_BAD";
|
||||
}
|
||||
case Token::Type::DEL_COMMA: {
|
||||
return "DEL_COMMA";
|
||||
}
|
||||
case Token::Type::DEL_COLON: {
|
||||
return "DEL_COLON";
|
||||
}
|
||||
case Token::Type::DEL_BRACE_L: {
|
||||
return "DEL_BRACE_L";
|
||||
}
|
||||
case Token::Type::DEL_BRACE_R: {
|
||||
return "DEL_BRACE_R";
|
||||
}
|
||||
case Token::Type::DEL_BRACKET_L: {
|
||||
return "DEL_BRACKET_L";
|
||||
}
|
||||
case Token::Type::DEL_BRACKET_R: {
|
||||
return "DEL_BRACKET_R";
|
||||
}
|
||||
case Token::Type::DEL_SQUARE_BRACKET_L: {
|
||||
return "DEL_SQUARE_BRACKET_L";
|
||||
}
|
||||
case Token::Type::DEL_SQUARE_BRACKET_R: {
|
||||
return "DEL_SQUARE_BRACKET_R";
|
||||
}
|
||||
case Token::Type::DEL_GT: {
|
||||
return "DEL_GT";
|
||||
}
|
||||
case Token::Type::DEL_LT: {
|
||||
return "DEL_LT";
|
||||
}
|
||||
case Token::Type::DEL_EQ: {
|
||||
return "DEL_EQ";
|
||||
}
|
||||
case Token::Type::DEL_DOT: {
|
||||
return "DEL_DOT";
|
||||
}
|
||||
case Token::Type::ID: {
|
||||
return "ID";
|
||||
}
|
||||
case Token::Type::ID_STRING: {
|
||||
return "ID_STRING";
|
||||
}
|
||||
default:
|
||||
return "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsQuote(char c)
|
||||
{
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
Lexer::Lexer() : curr_line_(nullptr)
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "element of class Lexer initialized";
|
||||
}
|
||||
|
||||
Lexer::~Lexer()
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "element of class Lexer destructed";
|
||||
}
|
||||
|
||||
Tokens Lexer::TokenizeString(const std::string &source_str)
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "started tokenizing of line " << lines_.size() + 1 << ": ";
|
||||
|
||||
lines_.emplace_back(source_str);
|
||||
|
||||
curr_line_ = &lines_.back();
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
|
||||
AnalyzeLine();
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "tokenization of line " << lines_.size() << " is successful";
|
||||
LOG(DEBUG, ASSEMBLER) << " tokens identified: ";
|
||||
|
||||
for (const auto &f_i : lines_.back().tokens) {
|
||||
LOG(DEBUG, ASSEMBLER) << "\n "
|
||||
<< std::string_view(&*(f_i.whole_line.begin() + f_i.bound_left),
|
||||
f_i.bound_right - f_i.bound_left)
|
||||
<< " (type: " << TokenTypeWhat(f_i.type) << ")";
|
||||
|
||||
LOG(DEBUG, ASSEMBLER);
|
||||
LOG(DEBUG, ASSEMBLER);
|
||||
}
|
||||
return std::pair<std::vector<Token>, Error>(lines_.back().tokens, err_);
|
||||
}
|
||||
|
||||
// End of line
|
||||
bool Lexer::Eol() const
|
||||
{
|
||||
return curr_line_->pos == curr_line_->end;
|
||||
}
|
||||
|
||||
// Return the type of token
|
||||
Token::Type Lexer::LexGetType(size_t beg, size_t end) const
|
||||
{
|
||||
if (FindDelim(curr_line_->buffer[beg]) != Token::Type::ID_BAD) { /* delimiter */
|
||||
return FindDelim(curr_line_->buffer[beg]);
|
||||
}
|
||||
|
||||
std::string_view p(&*(curr_line_->buffer.begin() + beg), end - beg);
|
||||
Token::Type type = Findkeyword(p);
|
||||
if (type != Token::Type::ID_BAD) {
|
||||
return type;
|
||||
}
|
||||
|
||||
type = FindOperation(p);
|
||||
if (type != Token::Type::ID_BAD) {
|
||||
return type;
|
||||
}
|
||||
|
||||
if (IsQuote(curr_line_->buffer[beg])) {
|
||||
return Token::Type::ID_STRING;
|
||||
}
|
||||
|
||||
return Token::Type::ID; // other
|
||||
}
|
||||
|
||||
// Handle string literal
|
||||
bool Lexer::LexString()
|
||||
{
|
||||
bool is_escape_seq = false;
|
||||
char quote = curr_line_->buffer[curr_line_->pos];
|
||||
size_t begin = curr_line_->pos;
|
||||
while (!Eol()) {
|
||||
++(curr_line_->pos);
|
||||
|
||||
char c = curr_line_->buffer[curr_line_->pos];
|
||||
|
||||
if (is_escape_seq) {
|
||||
is_escape_seq = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\\') {
|
||||
is_escape_seq = true;
|
||||
}
|
||||
|
||||
if (c == quote) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_line_->buffer[curr_line_->pos] != quote) {
|
||||
err_ = Error(std::string("Missing terminating ") + quote + " character", 0,
|
||||
Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER, "", begin, curr_line_->pos,
|
||||
curr_line_->buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
++(curr_line_->pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tokens handling: set the corresponding
|
||||
* elements bound_left and bound_right of the array tokens
|
||||
* to the first and last characters of a corresponding token.
|
||||
*
|
||||
* bound_r1 bound_r2 bound_r3
|
||||
* | | |
|
||||
* v v v
|
||||
* token1 token2 token3 ... token1 token2 token3 ...
|
||||
* => ^ ^ ^
|
||||
* | | |
|
||||
* bound1 bound2 bound3 ... bound_l1 bound_l2 bound_l3 ...
|
||||
*
|
||||
*/
|
||||
void Lexer::LexTokens()
|
||||
{
|
||||
if (Eol()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "token search started (line " << lines_.size() << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
|
||||
while (curr_line_->end > curr_line_->pos && isspace(curr_line_->buffer[curr_line_->end - 1]) != 0) {
|
||||
--(curr_line_->end);
|
||||
}
|
||||
|
||||
while (isspace(curr_line_->buffer[curr_line_->pos]) != 0 && !Eol()) {
|
||||
++(curr_line_->pos);
|
||||
}
|
||||
|
||||
size_t bound_right;
|
||||
size_t bound_left;
|
||||
|
||||
for (int i = 0; !Eol(); ++i) {
|
||||
bound_left = curr_line_->pos;
|
||||
|
||||
if (FindDelim(curr_line_->buffer[curr_line_->pos]) != Token::Type::ID_BAD) {
|
||||
++(curr_line_->pos);
|
||||
} else if (IsQuote(curr_line_->buffer[curr_line_->pos])) {
|
||||
if (!LexString()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
while (!Eol() && FindDelim(curr_line_->buffer[curr_line_->pos]) == Token::Type::ID_BAD &&
|
||||
isspace(curr_line_->buffer[curr_line_->pos]) == 0) {
|
||||
++(curr_line_->pos);
|
||||
}
|
||||
}
|
||||
|
||||
bound_right = curr_line_->pos;
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "token identified (line " << lines_.size() << ", "
|
||||
<< "token " << curr_line_->tokens.size() + 1 << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + bound_left), bound_right - bound_left)
|
||||
<< " ("
|
||||
<< "type: " << TokenTypeWhat(LexGetType(bound_left, bound_right)) << ")";
|
||||
|
||||
curr_line_->tokens.emplace_back(bound_left, bound_right, LexGetType(bound_left, bound_right),
|
||||
curr_line_->buffer);
|
||||
|
||||
while (isspace(curr_line_->buffer[curr_line_->pos]) != 0 && !Eol()) {
|
||||
++(curr_line_->pos);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "all tokens identified (line " << lines_.size() << ")";
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore comments:
|
||||
* find PARSE_COMMENT_MARKER and move line->end to another position
|
||||
* next after the last character of the last significant (not a comment)
|
||||
* element in a current line: line->buffer.
|
||||
*
|
||||
* Ex:
|
||||
* [Label:] operation operand[,operand] [# comment]
|
||||
*
|
||||
* L1: mov v0, v1 # moving! L1: mov v0, v1 # moving!
|
||||
* ^ => ^
|
||||
* | |
|
||||
* end end
|
||||
*/
|
||||
void Lexer::LexPreprocess()
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "started removing comments (line " << lines_.size() << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
|
||||
size_t cmt_pos;
|
||||
bool inside_str_lit;
|
||||
|
||||
// Searching for comment marker located outside of the string literals.
|
||||
inside_str_lit = curr_line_->buffer.size() > 0 && curr_line_->buffer[0] == '\"';
|
||||
cmt_pos = -1;
|
||||
while ((cmt_pos = curr_line_->buffer.find_first_of("\"#", cmt_pos + 1)) != std::string::npos) {
|
||||
if (cmt_pos != 0 && curr_line_->buffer[cmt_pos - 1] != '\\' && curr_line_->buffer[cmt_pos] == '\"') {
|
||||
inside_str_lit = !inside_str_lit;
|
||||
} else if (curr_line_->buffer[cmt_pos] == PARSE_COMMENT_MARKER && !inside_str_lit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmt_pos != std::string::npos) {
|
||||
curr_line_->end = cmt_pos;
|
||||
}
|
||||
|
||||
while (curr_line_->end > curr_line_->pos && isspace(curr_line_->buffer[curr_line_->end - 1]) != 0) {
|
||||
--(curr_line_->end);
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "comments removed (line " << lines_.size() << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
}
|
||||
|
||||
void Lexer::SkipSpace()
|
||||
{
|
||||
while (!Eol() && isspace(curr_line_->buffer[curr_line_->pos]) != 0) {
|
||||
++(curr_line_->pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::AnalyzeLine()
|
||||
{
|
||||
LexPreprocess();
|
||||
|
||||
SkipSpace();
|
||||
|
||||
LexTokens();
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_ASSEMBLER_LEXER_H_
|
||||
#define PANDA_ASSEMBLER_LEXER_H_
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "define.h"
|
||||
#include "error.h"
|
||||
#include "isa.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Token {
|
||||
enum class Type {
|
||||
ID_BAD = 0,
|
||||
/* delimiters */
|
||||
DEL_COMMA, /* , */
|
||||
DEL_COLON, /* : */
|
||||
DEL_BRACE_L, /* { */
|
||||
DEL_BRACE_R, /* } */
|
||||
DEL_BRACKET_L, /* ( */
|
||||
DEL_BRACKET_R, /* ) */
|
||||
DEL_SQUARE_BRACKET_L, /* [ */
|
||||
DEL_SQUARE_BRACKET_R, /* ] */
|
||||
DEL_GT, /* > */
|
||||
DEL_LT, /* < */
|
||||
DEL_EQ, /* = */
|
||||
DEL_DOT, /* . */
|
||||
ID, /* other */
|
||||
ID_STRING, /* string literal */
|
||||
OPERATION, /* special */
|
||||
#define OPLIST(inst_code, name, optype, width, flags, dst_idx, src_idxs) ID_OP_##inst_code, /* command type list */
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)
|
||||
#undef OPLIST
|
||||
KEYWORD, /* special */
|
||||
#define KEYWORDS(name, inst_code) ID_##inst_code, /* keyword type list */
|
||||
KEYWORDS_LIST(KEYWORDS)
|
||||
#undef KEYWORDS
|
||||
};
|
||||
|
||||
std::string whole_line;
|
||||
size_t bound_left; /* right and left bounds of tokens */
|
||||
size_t bound_right;
|
||||
Type type;
|
||||
|
||||
Token() : Token(0, 0, Type::ID_BAD, "") {}
|
||||
|
||||
Token(size_t b_l, size_t b_r, Type t, std::string beg_of_line)
|
||||
: whole_line(std::move(beg_of_line)), bound_left(b_l), bound_right(b_r), type(t)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using Tokens = std::pair<std::vector<Token>, Error>;
|
||||
|
||||
using TokenSet = const std::vector<std::vector<Token>>;
|
||||
|
||||
struct Line {
|
||||
std::vector<Token> tokens;
|
||||
std::string buffer; /* raw line, as read from the file */
|
||||
size_t pos; /* current line position */
|
||||
size_t end;
|
||||
|
||||
explicit Line(std::string str) : buffer(std::move(str)), pos(0), end(buffer.size()) {}
|
||||
};
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
Lexer();
|
||||
~Lexer();
|
||||
NO_MOVE_SEMANTIC(Lexer);
|
||||
NO_COPY_SEMANTIC(Lexer);
|
||||
|
||||
/*
|
||||
* The main function of Tokenizing, which takes a string.
|
||||
* Returns a vector of tokens.
|
||||
*/
|
||||
Tokens TokenizeString(const std::string &);
|
||||
|
||||
private:
|
||||
std::vector<Line> lines_;
|
||||
Line *curr_line_;
|
||||
Error err_;
|
||||
|
||||
bool Eol() const; /* end of line */
|
||||
bool LexString();
|
||||
void LexTokens();
|
||||
void LexPreprocess();
|
||||
void SkipSpace();
|
||||
void AnalyzeLine();
|
||||
Token::Type LexGetType(size_t, size_t) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns a string representation of a token type.
|
||||
*/
|
||||
std::string_view TokenTypeWhat(Token::Type);
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_LEXER_H_
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_MANGLING_H_
|
||||
#define PANDA_ASSEMBLER_MANGLING_H_
|
||||
|
||||
#include "assembly-function.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace panda::pandasm {
|
||||
static std::string MANGLE_BEGIN = ":";
|
||||
static std::string MANGLE_SEPARATOR = ";";
|
||||
|
||||
inline std::string MangleFunctionName(const std::string &name, const std::vector<pandasm::Function::Parameter> ¶ms,
|
||||
const pandasm::Type &return_type)
|
||||
{
|
||||
std::string mangle_name {name};
|
||||
mangle_name += MANGLE_BEGIN;
|
||||
for (const auto &p : params) {
|
||||
mangle_name += p.type.GetName() + MANGLE_SEPARATOR;
|
||||
}
|
||||
mangle_name += return_type.GetName() + MANGLE_SEPARATOR;
|
||||
|
||||
return mangle_name;
|
||||
}
|
||||
|
||||
inline std::string DeMangleName(const std::string &name)
|
||||
{
|
||||
auto iter = name.find_first_of(MANGLE_BEGIN);
|
||||
if (iter != std::string::npos) {
|
||||
return name.substr(0, name.find_first_of(MANGLE_BEGIN));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
inline std::string MangleFieldName(const std::string &name, const pandasm::Type &type)
|
||||
{
|
||||
std::string mangle_name {name};
|
||||
mangle_name += MANGLE_BEGIN;
|
||||
mangle_name += type.GetName() + MANGLE_SEPARATOR;
|
||||
return mangle_name;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_MANGLING_H_
|
||||
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* 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 "meta.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "utils/expected.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::optional<Metadata::Error> Metadata::ValidateSize(std::string_view value) const
|
||||
{
|
||||
constexpr size_t SIZE = 10;
|
||||
|
||||
if (!std::all_of(value.cbegin(), value.cend(), ::isdigit)) {
|
||||
return Error("Unsigned interger value expected", Error::Type::INVALID_VALUE);
|
||||
}
|
||||
|
||||
strtoul(value.data(), nullptr, SIZE);
|
||||
if (errno == ERANGE) {
|
||||
return Error("Value is out of range", Error::Type::INVALID_VALUE);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ItemMetadata::IsForeign() const
|
||||
{
|
||||
return GetAttribute("external");
|
||||
}
|
||||
|
||||
static panda::pandasm::Value::Type GetType(std::string_view value)
|
||||
{
|
||||
using VType = panda::pandasm::Value::Type;
|
||||
static std::unordered_map<std::string_view, VType> types {
|
||||
{"u1", VType::U1}, {"i8", VType::I8}, {"u8", VType::U8},
|
||||
{"i16", VType::I16}, {"u16", VType::U16}, {"i32", VType::I32},
|
||||
{"u32", VType::U32}, {"i64", VType::I64}, {"u64", VType::U64},
|
||||
{"f32", VType::F32}, {"f64", VType::F64}, {"string", VType::STRING},
|
||||
{"class", VType::RECORD}, {"enum", VType::ENUM}, {"annotation", VType::ANNOTATION},
|
||||
{"array", VType::ARRAY}, {"method", VType::METHOD}};
|
||||
|
||||
return types[value];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static T ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>, "T must be integral type");
|
||||
|
||||
constexpr T MIN = std::numeric_limits<T>::min();
|
||||
constexpr T MAX = std::numeric_limits<T>::max();
|
||||
|
||||
if constexpr (std::is_signed_v<T>) {
|
||||
auto v = ConvertFromString<int64_t>(value, end);
|
||||
if (v < MIN || v > MAX) {
|
||||
errno = ERANGE;
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
|
||||
if constexpr (!std::is_signed_v<T>) {
|
||||
auto v = ConvertFromString<uint64_t>(value, end);
|
||||
if (v < MIN || v > MAX) {
|
||||
errno = ERANGE;
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int64_t ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return static_cast<int64_t>(strtoll(value.data(), end, 0));
|
||||
}
|
||||
|
||||
template <>
|
||||
uint64_t ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return static_cast<uint64_t>(strtoull(value.data(), end, 0));
|
||||
}
|
||||
|
||||
template <>
|
||||
float ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return strtof(value.data(), end);
|
||||
}
|
||||
|
||||
template <>
|
||||
double ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return strtod(value.data(), end);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static Expected<T, Metadata::Error> ConvertFromString(std::string_view value)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>, "T must be arithmetic type");
|
||||
|
||||
char *end = nullptr;
|
||||
auto v = ConvertFromString<T>(value, &end);
|
||||
|
||||
if (end != value.data() + value.length()) {
|
||||
return Unexpected(Metadata::Error("Excepted integer literal", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
if (errno == ERANGE) {
|
||||
errno = 0;
|
||||
return Unexpected(Metadata::Error("Value is out of range", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
|
||||
template <Value::Type type, class T = ValueTypeHelperT<type>>
|
||||
static Expected<ScalarValue, Metadata::Error> CreatePrimitiveValue(std::string_view value,
|
||||
T max_value = std::numeric_limits<T>::max())
|
||||
{
|
||||
auto res = ConvertFromString<T>(value);
|
||||
if (!res) {
|
||||
return Unexpected(res.Error());
|
||||
}
|
||||
|
||||
auto converted = res.Value();
|
||||
if (converted > max_value) {
|
||||
return Unexpected(Metadata::Error("Value is out of range", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
return ScalarValue::Create<type>(converted);
|
||||
}
|
||||
|
||||
// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE)
|
||||
static Expected<ScalarValue, Metadata::Error> CreateValue(
|
||||
Value::Type type, std::string_view value,
|
||||
const std::unordered_map<std::string, std::unique_ptr<AnnotationData>> &annotation_id_map = {})
|
||||
{
|
||||
switch (type) {
|
||||
case Value::Type::U1: {
|
||||
return CreatePrimitiveValue<Value::Type::U1>(value, 1);
|
||||
}
|
||||
case Value::Type::I8: {
|
||||
return CreatePrimitiveValue<Value::Type::I8>(value);
|
||||
}
|
||||
case Value::Type::U8: {
|
||||
return CreatePrimitiveValue<Value::Type::U8>(value);
|
||||
}
|
||||
case Value::Type::I16: {
|
||||
return CreatePrimitiveValue<Value::Type::I16>(value);
|
||||
}
|
||||
case Value::Type::U16: {
|
||||
return CreatePrimitiveValue<Value::Type::U16>(value);
|
||||
}
|
||||
case Value::Type::I32: {
|
||||
return CreatePrimitiveValue<Value::Type::I32>(value);
|
||||
}
|
||||
case Value::Type::U32: {
|
||||
return CreatePrimitiveValue<Value::Type::U32>(value);
|
||||
}
|
||||
case Value::Type::I64: {
|
||||
return CreatePrimitiveValue<Value::Type::I64>(value);
|
||||
}
|
||||
case Value::Type::U64: {
|
||||
return CreatePrimitiveValue<Value::Type::U64>(value);
|
||||
}
|
||||
case Value::Type::F32: {
|
||||
return CreatePrimitiveValue<Value::Type::F32>(value);
|
||||
}
|
||||
case Value::Type::F64: {
|
||||
return CreatePrimitiveValue<Value::Type::F64>(value);
|
||||
}
|
||||
case Value::Type::STRING: {
|
||||
return ScalarValue::Create<Value::Type::STRING>(value);
|
||||
}
|
||||
case Value::Type::RECORD: {
|
||||
return ScalarValue::Create<Value::Type::RECORD>(Type::FromName(value));
|
||||
}
|
||||
case Value::Type::METHOD: {
|
||||
return ScalarValue::Create<Value::Type::METHOD>(value);
|
||||
}
|
||||
case Value::Type::ENUM: {
|
||||
return ScalarValue::Create<Value::Type::ENUM>(value);
|
||||
}
|
||||
case Value::Type::ANNOTATION: {
|
||||
auto it = annotation_id_map.find(std::string(value));
|
||||
if (it == annotation_id_map.cend()) {
|
||||
return Unexpected(Metadata::Error("Unknown annotation id", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
auto annotation_value = it->second.get();
|
||||
return ScalarValue::Create<Value::Type::ANNOTATION>(*annotation_value);
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::AnnotationElementBuilder::AddValue(
|
||||
std::string_view value, const std::unordered_map<std::string, std::unique_ptr<AnnotationData>> &annotation_id_map)
|
||||
{
|
||||
ASSERT(type_.has_value());
|
||||
|
||||
auto type = type_.value();
|
||||
if (type == Value::Type::ARRAY) {
|
||||
ASSERT(component_type_.has_value());
|
||||
type = component_type_.value();
|
||||
}
|
||||
|
||||
auto res = CreateValue(type, value, annotation_id_map);
|
||||
if (!res) {
|
||||
return res.Error();
|
||||
}
|
||||
|
||||
values_.push_back(res.Value());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::Store(std::string_view attribute)
|
||||
{
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element isn't completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
return Metadata::Store(attribute);
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpRecordAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element isn't completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
InitializeAnnotationBuilder(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpIdAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotation() || IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation record attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_builder_.HasId()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation id attribute already defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
annotation_builder_.SetId(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementNameAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotation()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation record attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Previous annotation element isn't defined completely",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
InitializeAnnotationElementBuilder(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementTypeAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element name attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_element_builder_.IsTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element type attribute already defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
annotation_element_builder_.SetType(GetType(value));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementArrayComponentTypeAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element name attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (!annotation_element_builder_.IsArray()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) + "'. Annotation element type isn't array",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_element_builder_.IsComponentTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element array component type attribute already defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
annotation_element_builder_.SetComponentType(GetType(value));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementValueAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element name attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (!annotation_element_builder_.IsTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element type attribute isn't defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_element_builder_.IsArray() && !annotation_element_builder_.IsComponentTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element array component type attribute isn't defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (!annotation_element_builder_.IsArray() && annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element is completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
return annotation_element_builder_.AddValue(value, id_map_);
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::StoreValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
auto err = Metadata::StoreValue(attribute, value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (IsAnnotationRecordAttribute(attribute)) {
|
||||
return MeetExpRecordAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationIdAttribute(attribute)) {
|
||||
return MeetExpIdAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementNameAttribute(attribute)) {
|
||||
return MeetExpElementNameAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementTypeAttribute(attribute)) {
|
||||
return MeetExpElementTypeAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementArrayComponentTypeAttribute(attribute)) {
|
||||
return MeetExpElementArrayComponentTypeAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementValueAttribute(attribute)) {
|
||||
return MeetExpElementValueAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element isn't completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::ValidateData()
|
||||
{
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error("Annotation element isn't completely defined", Error::Type::MISSING_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
return Metadata::ValidateData();
|
||||
}
|
||||
|
||||
std::string RecordMetadata::GetBase() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> RecordMetadata::GetInterfaces() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsRuntimeAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsTypeAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsRuntimeTypeAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FunctionMetadata::HasImplementation() const
|
||||
{
|
||||
return !(ACC_ABSTRACT & GetAccessFlags()) && !(ACC_NATIVE & GetAccessFlags());
|
||||
}
|
||||
|
||||
bool FunctionMetadata::IsCtor() const
|
||||
{
|
||||
return GetAttribute("ctor");
|
||||
}
|
||||
|
||||
bool FunctionMetadata::IsCctor() const
|
||||
{
|
||||
return GetAttribute("cctor");
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> FieldMetadata::StoreValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
auto err = ItemMetadata::StoreValue(attribute, value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (IsValueAttribute(attribute)) {
|
||||
Value::Type value_type;
|
||||
if (!field_type_.IsObject()) {
|
||||
value_type = GetType(field_type_.GetName());
|
||||
} else {
|
||||
value_type = Value::Type::STRING;
|
||||
}
|
||||
|
||||
auto res = CreateValue(value_type, value);
|
||||
if (!res) {
|
||||
return res.Error();
|
||||
}
|
||||
|
||||
value_ = res.Value();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#include <meta_gen.h>
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_META_H_
|
||||
#define PANDA_ASSEMBLER_META_H_
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "annotation.h"
|
||||
#include "modifiers.h"
|
||||
|
||||
#include "assembly-type.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class Metadata {
|
||||
public:
|
||||
class Error {
|
||||
public:
|
||||
enum class Type {
|
||||
INVALID_VALUE,
|
||||
MISSING_ATTRIBUTE,
|
||||
MISSING_VALUE,
|
||||
MULTIPLE_ATTRIBUTE,
|
||||
UNEXPECTED_ATTRIBUTE,
|
||||
UNEXPECTED_VALUE,
|
||||
UNKNOWN_ATTRIBUTE
|
||||
};
|
||||
|
||||
Error(std::string msg, Type type) : msg_(std::move(msg)), type_(type) {}
|
||||
~Error() = default;
|
||||
DEFAULT_MOVE_SEMANTIC(Error);
|
||||
DEFAULT_COPY_SEMANTIC(Error);
|
||||
|
||||
std::string GetMessage() const
|
||||
{
|
||||
return msg_;
|
||||
}
|
||||
|
||||
Type GetType() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string msg_;
|
||||
Type type_;
|
||||
};
|
||||
|
||||
Metadata() = default;
|
||||
|
||||
virtual ~Metadata() = default;
|
||||
|
||||
std::optional<Error> SetAttribute(std::string_view attribute)
|
||||
{
|
||||
auto err = Validate(attribute);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SetFlags(attribute);
|
||||
|
||||
return Store(attribute);
|
||||
}
|
||||
|
||||
void RemoveAttribute(const std::string &attribute)
|
||||
{
|
||||
RemoveFlags(attribute);
|
||||
|
||||
set_attributes_.erase(attribute);
|
||||
}
|
||||
|
||||
bool GetAttribute(const std::string &attribute) const
|
||||
{
|
||||
return set_attributes_.find(attribute) != set_attributes_.cend();
|
||||
}
|
||||
|
||||
std::optional<Error> SetAttributeValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
auto err = Validate(attribute, value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SetFlags(attribute, value);
|
||||
|
||||
return StoreValue(attribute, value);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetAttributeValues(const std::string &attribute) const
|
||||
{
|
||||
auto it = attributes_.find(attribute);
|
||||
if (it == attributes_.cend()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetAttributeValue(const std::string &attribute) const
|
||||
{
|
||||
auto values = GetAttributeValues(attribute);
|
||||
if (!values.empty()) {
|
||||
return values.front();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::unordered_set<std::string> &GetBoolAttributes() const
|
||||
{
|
||||
return set_attributes_;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::vector<std::string>> &GetAttributes() const
|
||||
{
|
||||
return attributes_;
|
||||
}
|
||||
|
||||
virtual std::optional<Error> ValidateData()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
DEFAULT_COPY_SEMANTIC(Metadata);
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(Metadata);
|
||||
|
||||
protected:
|
||||
virtual std::optional<Error> Validate(std::string_view attribute) const = 0;
|
||||
|
||||
virtual std::optional<Error> Validate(std::string_view attribute, std::string_view value) const = 0;
|
||||
|
||||
virtual std::optional<Error> StoreValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
std::string key(attribute);
|
||||
auto it = attributes_.find(key);
|
||||
if (it == attributes_.cend()) {
|
||||
std::tie(it, std::ignore) = attributes_.try_emplace(key);
|
||||
}
|
||||
|
||||
it->second.emplace_back(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
virtual std::optional<Error> Store(std::string_view attribute)
|
||||
{
|
||||
set_attributes_.emplace(attribute);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
virtual void SetFlags(std::string_view attribute) = 0;
|
||||
|
||||
virtual void SetFlags(std::string_view attribute, std::string_view value) = 0;
|
||||
|
||||
virtual void RemoveFlags(std::string_view attribute) = 0;
|
||||
|
||||
virtual void RemoveFlags(std::string_view attribute, std::string_view value) = 0;
|
||||
|
||||
bool HasAttribute(std::string_view attribute) const
|
||||
{
|
||||
std::string key(attribute);
|
||||
return GetAttribute(key) || GetAttributeValue(key);
|
||||
}
|
||||
|
||||
std::optional<Error> ValidateSize(std::string_view value) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> set_attributes_;
|
||||
std::unordered_map<std::string, std::vector<std::string>> attributes_;
|
||||
};
|
||||
|
||||
class AnnotationMetadata : public Metadata {
|
||||
public:
|
||||
const std::vector<AnnotationData> &GetAnnotations() const
|
||||
{
|
||||
return annotations_;
|
||||
}
|
||||
|
||||
void SetAnnotations(std::vector<AnnotationData> &&annotations)
|
||||
{
|
||||
annotations_ = std::forward<std::vector<AnnotationData>>(annotations);
|
||||
}
|
||||
|
||||
void AddAnnotations(const std::vector<AnnotationData> &annotations)
|
||||
{
|
||||
annotations_.insert(annotations_.end(), annotations.begin(), annotations.end());
|
||||
}
|
||||
|
||||
std::optional<Error> ValidateData() override;
|
||||
|
||||
protected:
|
||||
std::optional<Error> Store(std::string_view attribute) override;
|
||||
|
||||
std::optional<Error> StoreValue(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
virtual bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
class AnnotationElementBuilder {
|
||||
public:
|
||||
void Initialize(std::string_view name)
|
||||
{
|
||||
name_ = name;
|
||||
is_initialized_ = true;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
name_.clear();
|
||||
values_.clear();
|
||||
type_ = {};
|
||||
component_type_ = {};
|
||||
is_initialized_ = false;
|
||||
}
|
||||
|
||||
void SetType(Value::Type type)
|
||||
{
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
void SetComponentType(Value::Type type)
|
||||
{
|
||||
ASSERT(type != Value::Type::ARRAY);
|
||||
component_type_ = type;
|
||||
}
|
||||
|
||||
std::optional<Error> AddValue(
|
||||
std::string_view value,
|
||||
const std::unordered_map<std::string, std::unique_ptr<AnnotationData>> &annotation_id_map);
|
||||
|
||||
AnnotationElement CreateAnnotationElement()
|
||||
{
|
||||
if (IsArray()) {
|
||||
return AnnotationElement(name_,
|
||||
std::make_unique<ArrayValue>(component_type_.value(), std::move(values_)));
|
||||
}
|
||||
|
||||
return AnnotationElement(name_, std::make_unique<ScalarValue>(values_.front()));
|
||||
}
|
||||
|
||||
bool IsArray() const
|
||||
{
|
||||
return type_.value() == Value::Type::ARRAY;
|
||||
}
|
||||
|
||||
bool IsTypeSet() const
|
||||
{
|
||||
return type_.has_value();
|
||||
}
|
||||
|
||||
bool IsComponentTypeSet() const
|
||||
{
|
||||
return component_type_.has_value();
|
||||
}
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
return is_initialized_;
|
||||
}
|
||||
|
||||
bool IsCompleted() const
|
||||
{
|
||||
if (!IsTypeSet()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsArray() && !IsComponentTypeSet()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsArray() && values_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_initialized_ {false};
|
||||
std::string name_;
|
||||
std::optional<Value::Type> type_;
|
||||
std::optional<Value::Type> component_type_;
|
||||
std::vector<ScalarValue> values_;
|
||||
};
|
||||
|
||||
class AnnotationBuilder {
|
||||
public:
|
||||
void Initialize(std::string_view name)
|
||||
{
|
||||
name_ = name;
|
||||
is_initialized_ = true;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
name_.clear();
|
||||
elements_.clear();
|
||||
id_ = {};
|
||||
is_initialized_ = false;
|
||||
}
|
||||
|
||||
void SetId(std::string_view id)
|
||||
{
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
std::string GetId() const
|
||||
{
|
||||
ASSERT(HasId());
|
||||
return id_.value();
|
||||
}
|
||||
|
||||
void AddElement(AnnotationElement &&element)
|
||||
{
|
||||
elements_.push_back(std::forward<AnnotationElement>(element));
|
||||
}
|
||||
|
||||
std::unique_ptr<AnnotationData> CreateAnnotationData()
|
||||
{
|
||||
return std::make_unique<AnnotationData>(name_, std::move(elements_));
|
||||
};
|
||||
|
||||
void AddAnnnotationDataToVector(std::vector<AnnotationData> *annotations)
|
||||
{
|
||||
annotations->emplace_back(name_, std::move(elements_));
|
||||
}
|
||||
|
||||
bool HasId() const
|
||||
{
|
||||
return id_.has_value();
|
||||
}
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
return is_initialized_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::optional<std::string> id_;
|
||||
std::vector<AnnotationElement> elements_;
|
||||
bool is_initialized_ {false};
|
||||
};
|
||||
|
||||
std::optional<Metadata::Error> MeetExpRecordAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpIdAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementNameAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementTypeAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementArrayComponentTypeAttribute(std::string_view attribute,
|
||||
std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementValueAttribute(std::string_view attribute, std::string_view value);
|
||||
|
||||
void InitializeAnnotationBuilder(std::string_view name)
|
||||
{
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
annotation_builder_.Initialize(name);
|
||||
}
|
||||
|
||||
void ResetAnnotationBuilder()
|
||||
{
|
||||
ASSERT(IsParseAnnotation());
|
||||
|
||||
if (IsParseAnnotationElement() && annotation_element_builder_.IsCompleted()) {
|
||||
ResetAnnotationElementBuilder();
|
||||
}
|
||||
|
||||
if (annotation_builder_.HasId()) {
|
||||
id_map_.insert({annotation_builder_.GetId(), annotation_builder_.CreateAnnotationData()});
|
||||
} else {
|
||||
annotation_builder_.AddAnnnotationDataToVector(&annotations_);
|
||||
}
|
||||
|
||||
annotation_builder_.Reset();
|
||||
}
|
||||
|
||||
bool IsParseAnnotation() const
|
||||
{
|
||||
return annotation_builder_.IsInitialized();
|
||||
}
|
||||
|
||||
void InitializeAnnotationElementBuilder(std::string_view name)
|
||||
{
|
||||
if (IsParseAnnotationElement() && annotation_element_builder_.IsCompleted()) {
|
||||
ResetAnnotationElementBuilder();
|
||||
}
|
||||
|
||||
annotation_element_builder_.Initialize(name);
|
||||
}
|
||||
|
||||
void ResetAnnotationElementBuilder()
|
||||
{
|
||||
ASSERT(IsParseAnnotationElement());
|
||||
ASSERT(annotation_element_builder_.IsCompleted());
|
||||
|
||||
annotation_builder_.AddElement(annotation_element_builder_.CreateAnnotationElement());
|
||||
|
||||
annotation_element_builder_.Reset();
|
||||
}
|
||||
|
||||
bool IsParseAnnotationElement() const
|
||||
{
|
||||
return annotation_element_builder_.IsInitialized();
|
||||
}
|
||||
|
||||
AnnotationBuilder annotation_builder_;
|
||||
AnnotationElementBuilder annotation_element_builder_;
|
||||
std::vector<AnnotationData> annotations_;
|
||||
std::unordered_map<std::string, std::unique_ptr<AnnotationData>> id_map_;
|
||||
};
|
||||
|
||||
class ItemMetadata : public AnnotationMetadata {
|
||||
public:
|
||||
uint32_t GetAccessFlags() const
|
||||
{
|
||||
return access_flags_;
|
||||
}
|
||||
|
||||
void SetAccessFlags(uint32_t access_flags)
|
||||
{
|
||||
access_flags_ = access_flags;
|
||||
}
|
||||
|
||||
bool IsForeign() const;
|
||||
|
||||
private:
|
||||
uint32_t access_flags_ {0};
|
||||
};
|
||||
|
||||
class RecordMetadata : public ItemMetadata {
|
||||
public:
|
||||
virtual std::string GetBase() const;
|
||||
|
||||
virtual std::vector<std::string> GetInterfaces() const;
|
||||
|
||||
virtual bool IsAnnotation() const;
|
||||
|
||||
virtual bool IsRuntimeAnnotation() const;
|
||||
|
||||
virtual bool IsTypeAnnotation() const;
|
||||
|
||||
virtual bool IsRuntimeTypeAnnotation() const;
|
||||
|
||||
protected:
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
class FieldMetadata : public ItemMetadata {
|
||||
public:
|
||||
void SetFieldType(const Type &type)
|
||||
{
|
||||
field_type_ = type;
|
||||
}
|
||||
|
||||
Type GetFieldType() const
|
||||
{
|
||||
return field_type_;
|
||||
}
|
||||
|
||||
void SetValue(const ScalarValue &value)
|
||||
{
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
std::optional<ScalarValue> GetValue() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::optional<Error> StoreValue(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
virtual bool IsValueAttribute(std::string_view attribute)
|
||||
{
|
||||
return attribute == "value";
|
||||
}
|
||||
|
||||
private:
|
||||
Type field_type_;
|
||||
std::optional<ScalarValue> value_;
|
||||
};
|
||||
|
||||
class FunctionMetadata : public ItemMetadata {
|
||||
public:
|
||||
virtual bool HasImplementation() const;
|
||||
|
||||
virtual bool IsCtor() const;
|
||||
|
||||
virtual bool IsCctor() const;
|
||||
|
||||
protected:
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
class ParamMetadata : public AnnotationMetadata {
|
||||
protected:
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_META_H_
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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.
|
||||
|
||||
attributes:
|
||||
- name: external
|
||||
type: bool
|
||||
applicable_to:
|
||||
- record
|
||||
- field
|
||||
- function
|
||||
|
||||
- name: native
|
||||
type: bool
|
||||
flags: [ACC_NATIVE]
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: noimpl
|
||||
type: bool
|
||||
flags: [ACC_ABSTRACT]
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: static
|
||||
type: bool
|
||||
flags: [ACC_STATIC]
|
||||
applicable_to:
|
||||
- field
|
||||
- function
|
||||
|
||||
- name: ctor
|
||||
type: bool
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: cctor
|
||||
type: bool
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: value
|
||||
type: any
|
||||
multiple: false
|
||||
applicable_to:
|
||||
- field
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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 <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-emitter.h"
|
||||
#include "assembly-parser.h"
|
||||
#include "error.h"
|
||||
#include "lexer.h"
|
||||
#include "utils/expected.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/pandargs.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
void PrintError(const panda::pandasm::Error &e, const std::string &msg)
|
||||
{
|
||||
std::stringstream sos;
|
||||
std::cerr << msg << ": " << e.message << std::endl;
|
||||
sos << " Line " << e.line_number << ", Column " << e.pos + 1 << ": ";
|
||||
std::cerr << sos.str() << e.whole_line << std::endl;
|
||||
std::cerr << std::setw(static_cast<int>(e.pos + sos.str().size()) + 1) << "^" << std::endl;
|
||||
}
|
||||
|
||||
void PrintErrors(const panda::pandasm::ErrorList &warnings, const std::string &msg)
|
||||
{
|
||||
for (const auto &iter : warnings) {
|
||||
PrintError(iter, msg);
|
||||
}
|
||||
}
|
||||
|
||||
bool PrepareArgs(panda::PandArgParser &pa_parser, const panda::PandArg<std::string> &input_file,
|
||||
const panda::PandArg<std::string> &output_file, const panda::PandArg<std::string> &log_file,
|
||||
const panda::PandArg<bool> &help, const panda::PandArg<bool> &verbose, std::ifstream &inputfile,
|
||||
int argc, char **argv)
|
||||
{
|
||||
if (!pa_parser.Parse(argc, const_cast<const char **>(argv)) || input_file.GetValue().empty() ||
|
||||
output_file.GetValue().empty() || help.GetValue()) {
|
||||
std::cerr << "Usage:" << std::endl;
|
||||
std::cerr << "ark_asm [OPTIONS] INPUT_FILE OUTPUT_FILE" << std::endl << std::endl;
|
||||
std::cerr << "Supported options:" << std::endl << std::endl;
|
||||
std::cerr << pa_parser.GetHelpString() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (verbose.GetValue()) {
|
||||
if (log_file.GetValue().empty()) {
|
||||
panda::Logger::ComponentMask component_mask;
|
||||
component_mask.set(panda::Logger::Component::ASSEMBLER);
|
||||
panda::Logger::InitializeStdLogging(panda::Logger::Level::DEBUG, component_mask);
|
||||
} else {
|
||||
panda::Logger::ComponentMask component_mask;
|
||||
component_mask.set(panda::Logger::Component::ASSEMBLER);
|
||||
panda::Logger::InitializeFileLogging(log_file.GetValue(), panda::Logger::Level::DEBUG, component_mask);
|
||||
}
|
||||
}
|
||||
|
||||
inputfile.open(input_file.GetValue(), std::ifstream::in);
|
||||
|
||||
if (!inputfile) {
|
||||
std::cerr << "The input file does not exist." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tokenize(panda::pandasm::Lexer &lexer, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
std::ifstream &inputfile)
|
||||
{
|
||||
std::string s;
|
||||
|
||||
while (getline(inputfile, s)) {
|
||||
panda::pandasm::Tokens q = lexer.TokenizeString(s);
|
||||
|
||||
auto e = q.second;
|
||||
if (e.err != panda::pandasm::Error::ErrorType::ERR_NONE) {
|
||||
e.line_number = tokens.size() + 1;
|
||||
PrintError(e, "ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
tokens.push_back(q.first);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseProgram(panda::pandasm::Parser &parser, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
const panda::PandArg<std::string> &input_file,
|
||||
panda::Expected<panda::pandasm::Program, panda::pandasm::Error> &res)
|
||||
{
|
||||
res = parser.Parse(tokens, input_file.GetValue());
|
||||
if (!res) {
|
||||
PrintError(res.Error(), "ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpProgramInJson(panda::pandasm::Program &program, const panda::PandArg<std::string> &scopes_file)
|
||||
{
|
||||
if (!scopes_file.GetValue().empty()) {
|
||||
std::ofstream dump_file;
|
||||
dump_file.open(scopes_file.GetValue());
|
||||
|
||||
if (!dump_file) {
|
||||
std::cerr << "Failed to write scopes into the given file." << std::endl;
|
||||
return false;
|
||||
}
|
||||
dump_file << program.JsonDump();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitProgramInBinary(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
const panda::PandArg<bool> &size_stat)
|
||||
{
|
||||
auto emit_debug_info = !optimize.GetValue();
|
||||
std::map<std::string, size_t> stat;
|
||||
std::map<std::string, size_t> *statp = size_stat.GetValue() ? &stat : nullptr;
|
||||
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
|
||||
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = optimize.GetValue() ? &maps : nullptr;
|
||||
|
||||
if (!panda::pandasm::AsmEmitter::Emit(output_file.GetValue(), program, statp, mapsp, emit_debug_info)) {
|
||||
std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size_stat.GetValue()) {
|
||||
size_t total_size = 0;
|
||||
std::cout << "Panda file size statistic:" << std::endl;
|
||||
|
||||
for (auto [name, size] : stat) {
|
||||
std::cout << name << " section: " << size << std::endl;
|
||||
total_size += size;
|
||||
}
|
||||
|
||||
std::cout << "total: " << total_size << std::endl;
|
||||
}
|
||||
|
||||
pa_parser.DisableTail();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildFiles(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
panda::PandArg<bool> &size_stat, panda::PandArg<std::string> &scopes_file)
|
||||
{
|
||||
if (!DumpProgramInJson(program, scopes_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EmitProgramInBinary(program, pa_parser, output_file, optimize, size_stat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
panda::PandArg<bool> verbose("verbose", false, "Enable verbose output (will be printed to standard output)");
|
||||
panda::PandArg<std::string> log_file("log-file", "", "(--log-file FILENAME) Set log file name");
|
||||
panda::PandArg<std::string> scopes_file("dump-scopes", "",
|
||||
"(--dump-scopes FILENAME) Enable dump of scopes to file");
|
||||
panda::PandArg<bool> help("help", false, "Print this message and exit");
|
||||
panda::PandArg<bool> size_stat("size-stat", false, "Print panda file size statistic");
|
||||
panda::PandArg<bool> optimize("optimize", false, "Run the bytecode optimization");
|
||||
// tail arguments
|
||||
panda::PandArg<std::string> input_file("INPUT_FILE", "", "Path to the source assembly code");
|
||||
panda::PandArg<std::string> output_file("OUTPUT_FILE", "", "Path to the generated binary code");
|
||||
panda::PandArgParser pa_parser;
|
||||
pa_parser.Add(&verbose);
|
||||
pa_parser.Add(&help);
|
||||
pa_parser.Add(&log_file);
|
||||
pa_parser.Add(&scopes_file);
|
||||
pa_parser.Add(&size_stat);
|
||||
pa_parser.Add(&optimize);
|
||||
pa_parser.PushBackTail(&input_file);
|
||||
pa_parser.PushBackTail(&output_file);
|
||||
pa_parser.EnableTail();
|
||||
|
||||
std::ifstream inputfile;
|
||||
|
||||
if (!panda::pandasm::PrepareArgs(pa_parser, input_file, output_file, log_file, help, verbose, inputfile, argc,
|
||||
argv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "Lexical analysis:";
|
||||
|
||||
panda::pandasm::Lexer lexer;
|
||||
|
||||
std::vector<std::vector<panda::pandasm::Token>> tokens;
|
||||
|
||||
if (!Tokenize(lexer, tokens, inputfile)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "parsing:";
|
||||
|
||||
panda::pandasm::Parser parser;
|
||||
|
||||
panda::Expected<panda::pandasm::Program, panda::pandasm::Error> res;
|
||||
if (!panda::pandasm::ParseProgram(parser, tokens, input_file, res)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto &program = res.Value();
|
||||
|
||||
auto w = parser.ShowWarnings();
|
||||
if (!w.empty()) {
|
||||
panda::pandasm::PrintErrors(w, "WARNING");
|
||||
}
|
||||
|
||||
if (!panda::pandasm::BuildFiles(program, pa_parser, output_file, optimize, size_stat, scopes_file)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_PANDASM_H_
|
||||
#define PANDA_ASSEMBLER_PANDASM_H_
|
||||
|
||||
#include "utils/pandargs.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
void PrintError(const panda::pandasm::Error &e, const std::string &msg);
|
||||
|
||||
void PrintErrors(const panda::pandasm::ErrorList &warnings, const std::string &msg);
|
||||
|
||||
bool PrepareArgs(panda::PandArgParser &pa_parser, const panda::PandArg<std::string> &input_file,
|
||||
const panda::PandArg<std::string> &output_file, const panda::PandArg<std::string> &log_file,
|
||||
const panda::PandArg<bool> &help, const panda::PandArg<bool> &verbose, std::ifstream &inputfile,
|
||||
int argc, char **argv);
|
||||
|
||||
bool Tokenize(panda::pandasm::Lexer &lexer, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
std::ifstream &inputfile);
|
||||
|
||||
bool ParseProgram(panda::pandasm::Parser &parser, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
const panda::PandArg<std::string> &input_file,
|
||||
panda::Expected<panda::pandasm::Program, panda::pandasm::Error> &res);
|
||||
|
||||
bool DumpProgramInJson(panda::pandasm::Program &program, const panda::PandArg<std::string> &scopes_file);
|
||||
|
||||
bool EmitProgramInBinary(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
panda::PandArg<bool> &size_stat);
|
||||
|
||||
bool BuildFiles(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
panda::PandArg<bool> &size_stat, panda::PandArg<std::string> &scopes_file);
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_PANDASM_H_
|
||||
@@ -0,0 +1,83 @@
|
||||
# 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.
|
||||
|
||||
|
||||
.function i64 main(){
|
||||
ldai 30000
|
||||
sta v1
|
||||
newarr v1, i64[]
|
||||
sta.obj v0
|
||||
call.short init, v0, v1
|
||||
call.short bubblesort, v0, v0
|
||||
lda v1
|
||||
subi 1
|
||||
ldarr.64 v0
|
||||
return.64
|
||||
}
|
||||
|
||||
.function void init(i64[] a0, i32 a1){
|
||||
movi v2, 0
|
||||
loop:
|
||||
lda a1
|
||||
jeqz init_exit
|
||||
subi 1
|
||||
sta a1
|
||||
starr.64 a0, v2
|
||||
inci v2, 1
|
||||
lda v2
|
||||
jmp loop
|
||||
init_exit:
|
||||
return.void
|
||||
}
|
||||
|
||||
.function void bubblesort(i64[] a0){
|
||||
lenarr a0
|
||||
sta v1
|
||||
outer:
|
||||
ldai 1
|
||||
sta v2
|
||||
ldai 1
|
||||
inner:
|
||||
jge v1, inner_exit
|
||||
sta v3
|
||||
ldarr.64 a0
|
||||
sta v4
|
||||
lda v3
|
||||
subi 1
|
||||
sta v5
|
||||
ldarr.64 a0
|
||||
jlt v4, next
|
||||
call swap, a0, v5, v3, v0
|
||||
movi v2, 0
|
||||
next:
|
||||
lda v3
|
||||
addi 1
|
||||
jmp inner
|
||||
inner_exit:
|
||||
inci v1, -1
|
||||
lda v2
|
||||
jeqz outer
|
||||
return.void
|
||||
}
|
||||
|
||||
.function void swap(i64[] a0, i32 a1, i32 a2){
|
||||
lda a1
|
||||
ldarr.64 a0
|
||||
sta v3
|
||||
lda a2
|
||||
ldarr.64 a0
|
||||
starr.64 a0, a1
|
||||
lda v3
|
||||
starr.64 a0, a2
|
||||
return.void
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# 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.
|
||||
|
||||
.function i32 factorial (i32 a0) <> { #Calculation of factorial from a value in register a0
|
||||
ldai.64 1
|
||||
sta.64 v8
|
||||
while_1:
|
||||
lda.64 a0
|
||||
movi.64 v0, 1
|
||||
jle v0, endwhile_3
|
||||
body_2:
|
||||
mul v8, a0
|
||||
sta.64 v8
|
||||
lda.64 a0
|
||||
subi 1
|
||||
sta.64 a0
|
||||
jmp while_1
|
||||
endwhile_3:
|
||||
lda.64 v8
|
||||
return
|
||||
}
|
||||
|
||||
.function i32 entry () <> {
|
||||
movi.64 v0, 7
|
||||
call.short factorial, v0
|
||||
return
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
.function i64 main(){
|
||||
movi v1, 10
|
||||
newarr v0, v1, i64[]
|
||||
ldai 0
|
||||
main_loop:
|
||||
jge v1, main_ret
|
||||
sta v2
|
||||
call.short fibonacci, v2, v2
|
||||
starr.64 v0, v2
|
||||
lda v2
|
||||
addi 1
|
||||
jmp main_loop
|
||||
main_ret:
|
||||
lda v1
|
||||
subi 1
|
||||
ldarr.64 v0
|
||||
return.64
|
||||
}
|
||||
|
||||
.function i64 fibonacci(i64 a0){
|
||||
lda a0
|
||||
jnez non_zero
|
||||
return.64
|
||||
non_zero:
|
||||
ldai 1
|
||||
jne a0, non_one
|
||||
return.64
|
||||
non_one:
|
||||
lda a0
|
||||
subi 1
|
||||
sta a0
|
||||
subi 1
|
||||
sta v1
|
||||
call.short fibonacci, a0, a0
|
||||
sta a0
|
||||
call.short fibonacci, v1, a0
|
||||
add2.64 a0
|
||||
return.64
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 "assembly-parser.h"
|
||||
|
||||
// Autogenerated file -- DO NOT EDIT!
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
int64_t Parser::MnemonicToBuiltinId() {
|
||||
const auto token = context_.GiveToken();
|
||||
|
||||
--context_;
|
||||
const auto ins = context_.GiveToken();
|
||||
++context_;
|
||||
|
||||
% PandaBuiltins::builtins.each_with_index do |builtin, i|
|
||||
%
|
||||
<%= i != 0 ? "else " : "" %>if (token == "<%= builtin.mnemonic%>" && ins == "<%= builtin.insn%>") {
|
||||
return static_cast<int64_t>(<%= builtin.id%>);
|
||||
}
|
||||
%
|
||||
% end
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Parser::ParseOperandBuiltinMnemonic() {
|
||||
if (context_.err.err != Error::ErrorType::ERR_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*context_ != Token::Type::ID) {
|
||||
context_.err = GetError("Expected Mnemonic", Error::ErrorType::ERR_BAD_OPERAND);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto builtin_id = MnemonicToBuiltinId();
|
||||
if (builtin_id != -1) {
|
||||
curr_ins_->imms.insert(curr_ins_->imms.begin(), builtin_id);
|
||||
} else {
|
||||
context_.err = GetError("The non-public extension of ISA does not contain such a builtin", Error::ErrorType::ERR_BAD_MNEMONIC_NAME);
|
||||
return false;
|
||||
}
|
||||
|
||||
++context_;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "assembly-parser.h"
|
||||
#include "define.h"
|
||||
#include "lexer.h"
|
||||
#include "operand_types_print.h"
|
||||
|
||||
using namespace panda::pandasm;
|
||||
|
||||
% PandaBuiltins::builtins.each do |builtin|
|
||||
%
|
||||
TEST(builtinparsingtests, builtins_<%=builtin.insn.tr('.', '_')%>_id<%=builtin.id%>)
|
||||
{
|
||||
Parser p;
|
||||
std::string src = std::string(R"(
|
||||
.function void g() {
|
||||
<%=builtin.insn%> <%=builtin.mnemonic%>)"
|
||||
% PandaBuiltins::instructions.each do |insn|
|
||||
%
|
||||
% if (insn.mnemonic == builtin.insn)
|
||||
%
|
||||
% insn.sig.split(', ').each_with_index do |op, i|
|
||||
% if (i != 0)
|
||||
% if (op.start_with?('v'))
|
||||
", v<%=i%>"
|
||||
% elsif (op.start_with?('imm'))
|
||||
", <%=i%>"
|
||||
% elsif (op == 'type_id')
|
||||
", A"
|
||||
% elsif (op == 'method_id')
|
||||
", g"
|
||||
% elsif (op == 'string_id')
|
||||
", \"string_string\""
|
||||
% elsif (op == 'field_id')
|
||||
", A.B"
|
||||
% end
|
||||
% end
|
||||
% end
|
||||
%
|
||||
% end
|
||||
% end
|
||||
"\nreturn.void\n}\n");
|
||||
|
||||
auto res = p.Parse(src);
|
||||
|
||||
Error e = p.ShowError();
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
}
|
||||
%
|
||||
% end
|
||||
|
||||
% PandaBuiltins::instructions.each do |insn|
|
||||
%
|
||||
TEST(builtinparsingtests, builtins_<%=insn.mnemonic.tr('.', '_')%>_bad_mnemonic_name) {
|
||||
{
|
||||
Parser p;
|
||||
std::string src = std::string(R"(
|
||||
.function void g() {
|
||||
<%=insn.mnemonic%> wrong_mnemonic)"
|
||||
% insn.sig.split(', ').each_with_index do |op, i|
|
||||
% if (i != 0)
|
||||
% if (op.start_with?('v'))
|
||||
", v<%=i%>"
|
||||
% elsif (op == 'imm')
|
||||
", <%=i%>"
|
||||
% elsif (op == 'type_id')
|
||||
", A"
|
||||
% elsif (op == 'method_id')
|
||||
", g"
|
||||
% elsif (op == 'string_id')
|
||||
", \"string_string\""
|
||||
% elsif (op == 'field_id')
|
||||
", A.B"
|
||||
% end
|
||||
% end
|
||||
% end
|
||||
"\nreturn.void\n}\n");
|
||||
|
||||
auto res = p.Parse(src);
|
||||
|
||||
Error e = p.ShowError();
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_MNEMONIC_NAME);
|
||||
}
|
||||
}
|
||||
%
|
||||
% end
|
||||
|
||||
% PandaBuiltins::instructions.each do |insn|
|
||||
%
|
||||
TEST(builtinparsingtests, builtins_<%=insn.mnemonic.tr('.', '_')%>_bad_operand) {
|
||||
{
|
||||
Parser p;
|
||||
std::string src = std::string(R"(
|
||||
.record A {
|
||||
u1 B
|
||||
}
|
||||
.function void g() {
|
||||
<%=insn.mnemonic%> "")"
|
||||
% insn.sig.split(', ').each_with_index do |op, i|
|
||||
% if (i != 0)
|
||||
% if (op.start_with?('v'))
|
||||
", v<%=i%>"
|
||||
% elsif (op == 'imm')
|
||||
", <%=i%>"
|
||||
% elsif (op == 'type_id')
|
||||
", A"
|
||||
% elsif (op == 'method_id')
|
||||
", g"
|
||||
% elsif (op == 'string_id')
|
||||
", \"string_string\""
|
||||
% elsif (op == 'field_id')
|
||||
", A.B"
|
||||
% end
|
||||
% end
|
||||
% end
|
||||
"\nreturn.void\n}\n");
|
||||
|
||||
auto res = p.Parse(src);
|
||||
|
||||
Error e = p.ShowError();
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_OPERAND);
|
||||
}
|
||||
}
|
||||
%
|
||||
% end
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Autogenerated file -- DO NOT EDIT!
|
||||
|
||||
#include <initializer_list>
|
||||
#include "assembly-ins.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% signature = assembler_signature(group, insn.jump?)
|
||||
% signature_str = signature.map { |o| "#{o.type} #{o.name}" }.join(', ')
|
||||
inline Ins Create_<%= insn.asm_token %>(<%= signature_str %>)
|
||||
{
|
||||
Ins <%=insn.emitter_name%>_;
|
||||
<%=group.first.emitter_name%>_.opcode = Opcode::<%= insn.asm_token %>;
|
||||
% format = format_ops(insn.format)
|
||||
% format.each { |o| o.width = storage_width(o.width) }
|
||||
% count_reg = 0
|
||||
% format.each_with_index do |o, i|
|
||||
% if o.name.start_with?('v')
|
||||
% count_reg += 1
|
||||
% end
|
||||
% end
|
||||
% if count_reg > 0 then
|
||||
<%=group.first.emitter_name%>_.regs.reserve(<%= count_reg %>);
|
||||
% end
|
||||
% format.each_with_index do |o, i|
|
||||
% if o.name.start_with?('imm')
|
||||
% if insn.jump? == true
|
||||
<%=group.first.emitter_name%>_.ids.push_back(label);
|
||||
% else
|
||||
<%=group.first.emitter_name%>_.imms.emplace_back(<%= o.name %>);
|
||||
% end
|
||||
% elsif o.name.start_with?('id')
|
||||
<%=group.first.emitter_name%>_.ids.push_back(<%= o.name %>);
|
||||
% else
|
||||
<%=group.first.emitter_name%>_.regs.push_back(<%= o.name %>);
|
||||
% end
|
||||
% end
|
||||
return <%=insn.emitter_name%>_;
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#include <ins_create_builtins_api.h>
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Autogenerated file -- DO NOT EDIT!
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
% PandaBuiltins::builtins.each do |builtin|
|
||||
% i_mnemo = builtin.insn.tr('.', '_').upcase
|
||||
% b_mnemo = builtin.mnemonic.tr('.', '_').upcase
|
||||
% sig = []
|
||||
% args = ['BUILTIN_ID']
|
||||
%
|
||||
% # NB! This logic below is very simplistic. May need proper
|
||||
% # work with formats in builtinsapi.rb some day.
|
||||
% format_list = builtin.format.split("_");
|
||||
% format_list.each_index do |i|
|
||||
% next if i == 0
|
||||
% if format_list[i] == "v4" then
|
||||
% sig << "uint16_t v" + i.to_s
|
||||
% args << "v" + i.to_s
|
||||
% elsif format_list[i] == "v8" then
|
||||
% sig << "uint16_t v" + i.to_s
|
||||
% args << "v" + i.to_s
|
||||
% elsif format_list[i] == "id16"
|
||||
% sig << "std::string& id" + i.to_s
|
||||
% args << "id" + i.to_s
|
||||
% elsif format_list[i] == "id32"
|
||||
% sig << "std::string& id" + i.to_s
|
||||
% args << "id" + i.to_s
|
||||
|
||||
% elsif format_list[i] == "imm8"
|
||||
% sig << "uint8_t imm" + i.to_s
|
||||
% args << "imm" + i.to_s
|
||||
% elsif format_list[i] == "imm16"
|
||||
% sig << "uint16_t imm" + i.to_s
|
||||
% args << "imm" + i.to_s
|
||||
% end
|
||||
% end
|
||||
inline Ins Create_BUILTIN_<%= b_mnemo %>(<%= sig.join(', ') %>)
|
||||
{
|
||||
constexpr uint8_t BUILTIN_ID = <%= builtin.id %>;
|
||||
return panda::pandasm::Create_<%= i_mnemo %>(<%= args.join(', ') %>);
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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 "assembly-ins.h"
|
||||
#include "mangling.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
|
||||
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
|
||||
const std::unordered_map<std::string_view, panda::Label>& labels) const {
|
||||
if (!IsValidToEmit()) {
|
||||
std::cerr << "Invalid instruction: " << ToString() << std::endl;
|
||||
LOG(FATAL, ASSEMBLER);
|
||||
}
|
||||
switch(opcode) {
|
||||
% inst_map = Panda::instructions.collect { |i| [i.mnemonic, i] }.to_h
|
||||
% call_map = {
|
||||
% "call.short" => ["call.short"],
|
||||
% "call" => ["call.short", "call"],
|
||||
% "calli.dyn.short" => ["calli.dyn.short"],
|
||||
% "calli.dyn" => ["calli.dyn.short", "calli.dyn"],
|
||||
% "call.acc.short" => ["call.acc.short"],
|
||||
% "call.acc" => ["call.acc.short", "call.acc"],
|
||||
% "call.virt.short" => ["call.virt.short"],
|
||||
% "call.virt" => ["call.virt.short", "call.virt"],
|
||||
% "call.virt.acc.short" => ["call.virt.acc.short"],
|
||||
% "call.virt.acc" => ["call.virt.acc.short", "call.virt.acc"],
|
||||
% "call.dyn.short" => ["call.dyn.short"],
|
||||
% "call.dyn" => ["call.dyn.short", "call.dyn"],
|
||||
% "initobj.short" => ["initobj.short"],
|
||||
% "initobj" => ["initobj"],
|
||||
% "builtin.idr4" => ["builtin.idr4"],
|
||||
% "builtin.idr6" => ["builtin.idr6"]
|
||||
%}
|
||||
% Panda::instructions.group_by(&:mnemonic).each_pair do |mn, group|
|
||||
% insn = group[index_of_max(group.map(&:format).map(&:size))]
|
||||
%
|
||||
% def type(insn)
|
||||
% src_acc_ops = insn.acc_and_operands.select(&:src?)
|
||||
% src_acc_ops.size != 0 ? src_acc_ops.first.type : 'none'
|
||||
% end
|
||||
%
|
||||
% def op_size(insn)
|
||||
% type(insn)[1..-1].to_i
|
||||
% end
|
||||
%
|
||||
% def operands(insn, regs = "regs")
|
||||
% ops = []
|
||||
% nr = 0
|
||||
% ni = 0
|
||||
% insn.operands.each do |op|
|
||||
% if op.reg?
|
||||
% ops << "#{regs}[#{nr}]"
|
||||
% nr += 1
|
||||
% elsif op.imm?
|
||||
% if insn.jump?
|
||||
% ops << 'labels.find(ids[0])->second'
|
||||
% else
|
||||
% from_type, to_type = op_size(insn) == 64 ? ['double', 'int64_t'] : ['float', 'int32_t']
|
||||
% if insn.float?
|
||||
% ops << bit_cast("imms[#{ni}]", to_type, from_type)
|
||||
% elsif type(insn).start_with? 'u' # can hold both float and integer literals
|
||||
% ops << "std::holds_alternative<double>(imms[#{ni}]) ? #{bit_cast("imms[#{ni}]", to_type, from_type)} : std::get<int64_t>(imms[#{ni}])"
|
||||
% else
|
||||
% ops << "std::get<int64_t>(imms[#{ni}])"
|
||||
% end
|
||||
% end
|
||||
% ni += 1
|
||||
% elsif op.id?
|
||||
% if insn.properties.include?('method_id')
|
||||
% ops << 'methods.find(ids[0])->second->GetIndex(method)'
|
||||
% elsif insn.properties.include?('field_id')
|
||||
% ops << 'fields.find(ids[0])->second->GetIndex(method)'
|
||||
% elsif insn.properties.include?('type_id')
|
||||
% ops << 'classes.find(ids[0])->second->GetIndex(method)'
|
||||
% elsif insn.properties.include?('string_id')
|
||||
% ops << 'strings.find(ids[0])->second->GetOffset()'
|
||||
% elsif insn.properties.include?('literalarray_id')
|
||||
% ops << 'static_cast<uint32_t>(literalarrays.find(ids[0])->second->GetOffset())'
|
||||
% else
|
||||
% raise "Unexpected ID type"
|
||||
% end
|
||||
% else
|
||||
% raise "Unexpected operand type"
|
||||
% end
|
||||
% end
|
||||
% if insn.call?
|
||||
% ops << ops.shift
|
||||
% end
|
||||
% ops
|
||||
% end
|
||||
case Opcode::<%= insn.asm_token %>: {
|
||||
% if insn.properties.include?('method_id')
|
||||
if ((ids.size() == 0) || (methods.find(ids[0]) == methods.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.properties.include?('field_id')
|
||||
if ((ids.size() == 0) || (fields.find(ids[0]) == fields.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.properties.include?('type_id')
|
||||
if ((ids.size() == 0) || (classes.find(ids[0]) == classes.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.properties.include?('string_id')
|
||||
if ((ids.size() == 0) || (strings.find(ids[0]) == strings.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.jump?
|
||||
if ((ids.size() == 0) || (labels.find(ids[0]) == labels.cend())) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% regs_num = 0
|
||||
% imms_num = 0
|
||||
% insn.operands.each do |op|
|
||||
% if op.reg?
|
||||
% regs_num += 1
|
||||
% elsif op.imm?
|
||||
% imms_num += 1
|
||||
% end
|
||||
% end
|
||||
% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6?
|
||||
% if imms_num > 0
|
||||
if (imms.size() < <%= imms_num %>) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% elsif insn.jump?
|
||||
% if regs_num > 0
|
||||
if (regs.size() < <%= regs_num %>) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% else
|
||||
% if regs_num > 0 and imms_num > 0
|
||||
if (regs.size() < <%= regs_num %> || imms.size() < <%= imms_num %>) {
|
||||
return false;
|
||||
}
|
||||
% elsif regs_num > 0
|
||||
if (regs.size() < <%= regs_num %>) {
|
||||
return false;
|
||||
}
|
||||
% elsif imms_num > 0
|
||||
if (imms.size() < <%= imms_num %>) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% end
|
||||
% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6?
|
||||
auto registers = regs;
|
||||
% call_map[insn.mnemonic].map { |m| inst_map[m] }.each do |i|
|
||||
% registers = i.operands.select(&:reg?)
|
||||
if (registers.size() < <%= registers.size + 1 %>) {
|
||||
while (registers.size() < <%= registers.size %>) {
|
||||
registers.push_back(0);
|
||||
}
|
||||
emitter.<%= i.emitter_name %>(<%= operands(i, "registers").join(", ") %>);
|
||||
break;
|
||||
}
|
||||
% end
|
||||
% else
|
||||
emitter.<%= insn.emitter_name %>(<%= operands(insn).join(", ") %>);
|
||||
% end
|
||||
break;
|
||||
}
|
||||
% end
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#include "assembly-ins.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::string panda::pandasm::Ins::ToString(std::string endline, bool print_args /* = false */,
|
||||
size_t first_arg_idx /* = 0*/) const {
|
||||
std::string full_operation = "";
|
||||
std::string reg_case = "";
|
||||
if (this->set_label) {
|
||||
full_operation += this->label +": ";
|
||||
}
|
||||
switch(this->opcode) {
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% formats = group.map(&:format)
|
||||
% operands = insn.operands
|
||||
% properties = insn.properties
|
||||
case panda::pandasm::Opcode::<%= insn.asm_token%>: {
|
||||
full_operation += "<%= insn.mnemonic%>";
|
||||
% print_kind = case
|
||||
% when insn.call? || !insn.public?
|
||||
% 'PrintKind::CALL'
|
||||
% when insn.calli?
|
||||
% 'PrintKind::CALLI'
|
||||
% else
|
||||
% 'PrintKind::DEFAULT'
|
||||
% end
|
||||
full_operation += this->OperandsToString(<%= print_kind %>, print_args, first_arg_idx);
|
||||
} break;
|
||||
% end
|
||||
% Panda::pseudo_instructions.each do |insn|
|
||||
case panda::pandasm::Opcode::<%= insn.opcode %>: {
|
||||
full_operation += "<%= insn.opcode %>";
|
||||
full_operation += this->OperandsToString(PrintKind::DEFAULT, print_args, first_arg_idx);
|
||||
} break;
|
||||
% end
|
||||
case panda::pandasm::Opcode::INVALID: {
|
||||
full_operation += "";
|
||||
} break;
|
||||
}
|
||||
return full_operation + endline;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define PANDA_INSTRUCTION_LIST(_) \
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% formats = group.map(&:format)
|
||||
% pretty_format = insn.format.pretty.upcase.gsub(/[0-9]/, '')
|
||||
% pretty_format.gsub!('IMM', 'ID') if insn.jump?
|
||||
% pretty_format.gsub!('ID', 'TYPE') if insn.properties.include?('type_id')
|
||||
%
|
||||
% flags = ["InstFlags::NONE"]
|
||||
% flags << "InstFlags::CALL" if insn.simple_call?
|
||||
% flags << "InstFlags::JUMP" if insn.jump?
|
||||
% flags << "InstFlags::COND" if insn.conditional?
|
||||
% flags << "InstFlags::RETURN" if insn.return?
|
||||
% flags << "InstFlags::ACC_READ" if insn.properties.include? 'acc_read'
|
||||
% flags << "InstFlags::ACC_WRITE" if insn.properties.include? 'acc_write'
|
||||
% flags << "InstFlags::THROWING" if insn.throwing?
|
||||
% flags << "InstFlags::METHOD_ID" if insn.properties.include? 'method_id'
|
||||
% flags << "InstFlags::FIELD_ID" if insn.properties.include? 'field_id'
|
||||
% flags << "InstFlags::TYPE_ID" if insn.properties.include? 'type_id'
|
||||
% flags << "InstFlags::STRING_ID" if insn.properties.include? 'string_id'
|
||||
% flags << "InstFlags::LITERALARRAY_ID" if insn.properties.include? 'literalarray_id'
|
||||
% flags = "(#{flags.join(" | ")})"
|
||||
%
|
||||
% max_width = group.map do |i|
|
||||
% i.operands.select(&:reg?).map(&:width).max
|
||||
% end.max
|
||||
% max_width ||= 0
|
||||
%
|
||||
% regs = insn.operands.select(&:reg?)
|
||||
% dst_idx = regs.index(&:dst?) || 'INVALID_REG_IDX'
|
||||
% use_idxs = regs.size.times.select { |idx| regs[idx].src? } || []
|
||||
% use_idxs += (['INVALID_REG_IDX'] * (max_number_of_src_regs - use_idxs.size))
|
||||
% use_idxs = "(std::array<int, #{ max_number_of_src_regs }>{{#{use_idxs.join(', ')}}})"
|
||||
%
|
||||
_(<%= insn.asm_token %>, "<%= insn.mnemonic %>", <%= pretty_format %>, <%= max_width %>, <%= flags %>, <%= dst_idx %>, <%= use_idxs %>) \
|
||||
% end
|
||||
% Panda::pseudo_instructions.each do |insn|
|
||||
% use_idxs = insn.use_idxs + ['INVALID_REG_IDX'] * (max_number_of_src_regs - insn.use_idxs.size)
|
||||
% use_idxs = "(std::array<int, #{max_number_of_src_regs}>{{#{use_idxs.join(', ')}}})"
|
||||
_(<%= insn.opcode %> , "<%= insn.opcode %>", NONE, 0, (<%= insn.flags.join(" | ") %>), <%= insn.dst_idx %>, <%= use_idxs %>) \
|
||||
% end
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
% Metadata::item_types.each do |item_type|
|
||||
std::optional<Metadata::Error>
|
||||
<%= MetadataGen::class_name(item_type) %>::Validate(<%= MetadataGen::validate_arg_list(item_type, true).join(', ') %>) const {
|
||||
<%= MetadataGen::validate_body(item_type, true).join("\n") %>
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error>
|
||||
<%= MetadataGen::class_name(item_type) %>::Validate(<%= MetadataGen::validate_arg_list(item_type, false).join(', ') %>) const {
|
||||
<%= MetadataGen::validate_body(item_type, false).join("\n") %>
|
||||
}
|
||||
|
||||
% end
|
||||
%
|
||||
% Metadata::item_types.each do |item_type|
|
||||
void <%= MetadataGen::class_name(item_type) %>::SetFlags(<%= MetadataGen::flags_arg_list(item_type, true).join(', ') %>) {
|
||||
<%= MetadataGen::set_flags_body(item_type, true).join("\n") %>
|
||||
}
|
||||
|
||||
void <%= MetadataGen::class_name(item_type) %>::SetFlags(<%= MetadataGen::flags_arg_list(item_type, false).join(', ') %>) {
|
||||
<%= MetadataGen::set_flags_body(item_type, false).join("\n") %>
|
||||
}
|
||||
|
||||
void <%= MetadataGen::class_name(item_type) %>::RemoveFlags(<%= MetadataGen::flags_arg_list(item_type, true).join(', ') %>) {
|
||||
<%= MetadataGen::remove_flags_body(item_type, true).join("\n") %>
|
||||
}
|
||||
|
||||
void <%= MetadataGen::class_name(item_type) %>::RemoveFlags(<%= MetadataGen::flags_arg_list(item_type, false).join(', ') %>) {
|
||||
<%= MetadataGen::remove_flags_body(item_type, false).join("\n") %>
|
||||
}
|
||||
|
||||
% end
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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 "assembly-parser.h"
|
||||
#include "utils/number-utils.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
bool Parser::ParseOperands()
|
||||
{
|
||||
std::string_view p;
|
||||
uint64_t number;
|
||||
LOG(DEBUG, ASSEMBLER) << "operand search started (line " << line_stric_ << "): " << context_.tokens[0].whole_line;
|
||||
switch(context_.WaitFor())
|
||||
{
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% formats = group.map(&:format)
|
||||
% operands = insn.operands
|
||||
% properties = insn.properties
|
||||
% verification = insn.verification
|
||||
case Token::Type::ID_OP_<%= insn.asm_token%>: {
|
||||
% if insn.return? && !insn.properties.include?('dynamic')
|
||||
% if insn.return_obj?
|
||||
if (!curr_func_->return_type.IsObject()) {
|
||||
% elsif insn.return32?
|
||||
if (!curr_func_->return_type.IsPrim32()) {
|
||||
% elsif insn.return64?
|
||||
if (!curr_func_->return_type.IsPrim64()) {
|
||||
% elsif insn.return_void?
|
||||
if (!curr_func_->return_type.IsVoid()) {
|
||||
% end
|
||||
GetWarning("Unexpected return type. Correct the return type in the function definition: " +
|
||||
curr_func_->return_type.GetName(),
|
||||
Error::ErrorType::WAR_UNEXPECTED_RETURN_TYPE);
|
||||
}
|
||||
% end
|
||||
% required_args = operands.size
|
||||
% required_args = 1 if insn.call?
|
||||
% required_args = 2 if insn.calli?
|
||||
% operands.each_with_index do |op, j|
|
||||
%
|
||||
% if (j != 0)
|
||||
% if j >= required_args
|
||||
if (!context_.Mask()) {
|
||||
ParseOperandComma();
|
||||
}
|
||||
% else
|
||||
if (!context_.Mask()) {
|
||||
ParseOperandComma();
|
||||
} else {
|
||||
context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS);
|
||||
}
|
||||
% end
|
||||
% end
|
||||
%
|
||||
if (!context_.Mask()) {
|
||||
% if op.reg?
|
||||
|
||||
if (RegValidName()) {
|
||||
p = context_.GiveToken();
|
||||
p.remove_prefix(1);
|
||||
number = ToNumber(p);
|
||||
size_t reg_width = curr_func_->ins.back().MaxRegEncodingWidth();
|
||||
if ((1ull << reg_width) <= number) {
|
||||
context_.err = GetError("Register width mismatch.", Error::ErrorType::ERR_BAD_OPERAND);
|
||||
}
|
||||
} else if (context_.err.err == Error::ErrorType::ERR_NONE) {
|
||||
context_.err = GetError("Invalid name of register.", Error::ErrorType::ERR_BAD_NAME_REG);
|
||||
}
|
||||
|
||||
ParseOperandVreg();
|
||||
% elsif op.imm?
|
||||
% if (!insn.public? && j == 0)
|
||||
ParseOperandBuiltinMnemonic();
|
||||
% elsif properties.include?("jump")
|
||||
ParseOperandLabel();
|
||||
% else
|
||||
% if properties.include?("float")
|
||||
ParseOperandFloat();
|
||||
% else
|
||||
ParseOperandInteger();
|
||||
% end
|
||||
% end
|
||||
% elsif op.id?
|
||||
% if properties.include?("type_id")
|
||||
% if (verification.include?("type_id_array"))
|
||||
ParseOperandType(Type::VerificationType::TYPE_ID_ARRAY);
|
||||
% elsif (verification.include?("type_id_object"))
|
||||
ParseOperandType(Type::VerificationType::TYPE_ID_OBJECT);
|
||||
% elsif (verification.include?("type_id_any_object"))
|
||||
ParseOperandType(Type::VerificationType::TYPE_ID_ANY_OBJECT);
|
||||
% end
|
||||
% elsif properties.include?("string_id")
|
||||
ParseOperandString();
|
||||
% elsif properties.include?("method_id")
|
||||
ParseOperandCall();
|
||||
% elsif properties.include?("field_id")
|
||||
ParseOperandField();
|
||||
% else
|
||||
ParseOperandId();
|
||||
% end
|
||||
% end
|
||||
%
|
||||
% if (j >= required_args) && (operands.size > 0)
|
||||
}
|
||||
% elsif operands.size > 0
|
||||
} else {
|
||||
context_.err = GetError("Expected more arguments.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS);
|
||||
}
|
||||
% end
|
||||
% end
|
||||
ParseOperandNone();
|
||||
} break;
|
||||
%end
|
||||
default:
|
||||
context_.err = GetError("No such operation.", Error::ErrorType::ERR_BAD_NONEXISTING_OPERATION);
|
||||
return false;
|
||||
}
|
||||
return context_.Mask();
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -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 "assembly-parser.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
inline std::string OperandTypePrint(panda::pandasm::Opcode op) {
|
||||
switch (op) {
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% operands = insn.operands
|
||||
% properties = insn.properties
|
||||
case Opcode::<%= group.first.asm_token%>: {
|
||||
% operands_list = operands.map do |op|
|
||||
% if op.reg?
|
||||
% 'reg'
|
||||
% elsif op.imm?
|
||||
% properties.include?('jump') ? 'label' : 'imm'
|
||||
% elsif op.id?
|
||||
% if properties.include?('type_id')
|
||||
% 'type'
|
||||
% elsif properties.include?('string_id')
|
||||
% 'string'
|
||||
% elsif properties.include?('method_id')
|
||||
% 'call'
|
||||
% else
|
||||
% 'id'
|
||||
% end
|
||||
% end
|
||||
% end.join('_')
|
||||
% operands_list = 'none' if operands_list == ''
|
||||
return "<%= operands_list%>";
|
||||
};
|
||||
%end
|
||||
default:
|
||||
return "undefined";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
@@ -0,0 +1,871 @@
|
||||
/*
|
||||
* 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 <iomanip>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include "annotation_data_accessor.h"
|
||||
#include "assembly-emitter.h"
|
||||
#include "assembly-parser.h"
|
||||
#include "class_data_accessor-inl.h"
|
||||
#include "code_data_accessor-inl.h"
|
||||
#include "debug_data_accessor-inl.h"
|
||||
#include "field_data_accessor-inl.h"
|
||||
#include "file_items.h"
|
||||
#include "lexer.h"
|
||||
#include "method_data_accessor-inl.h"
|
||||
#include "param_annotations_data_accessor.h"
|
||||
#include "proto_data_accessor-inl.h"
|
||||
#include "utils/span.h"
|
||||
#include "utils/leb128.h"
|
||||
#include "utils/utf.h"
|
||||
|
||||
namespace panda::test {
|
||||
|
||||
using namespace panda::pandasm;
|
||||
|
||||
static const uint8_t *GetTypeDescriptor(const std::string &name, std::string *storage)
|
||||
{
|
||||
*storage = "L" + name + ";";
|
||||
std::replace(storage->begin(), storage->end(), '.', '/');
|
||||
return utf::CStringAsMutf8(storage->c_str());
|
||||
}
|
||||
|
||||
TEST(emittertests, test)
|
||||
{
|
||||
Parser p;
|
||||
|
||||
auto source = R"( # 1
|
||||
.record R { # 2
|
||||
i32 sf <static> # 3
|
||||
i8 if # 4
|
||||
} # 5
|
||||
# 6
|
||||
.function void main() { # 7
|
||||
return.void # 8
|
||||
} # 9
|
||||
)";
|
||||
|
||||
std::string source_filename = "source.pa";
|
||||
auto res = p.Parse(source, source_filename);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
// Check _GLOBAL class
|
||||
{
|
||||
std::string descriptor;
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
ASSERT_FALSE(pf->IsExternal(class_id));
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
ASSERT_EQ(cda.GetSuperClassId().GetOffset(), 0U);
|
||||
ASSERT_EQ(cda.GetAccessFlags(), ACC_PUBLIC);
|
||||
ASSERT_EQ(cda.GetFieldsNumber(), 0U);
|
||||
ASSERT_EQ(cda.GetMethodsNumber(), 1U);
|
||||
ASSERT_EQ(cda.GetIfacesNumber(), 0U);
|
||||
|
||||
ASSERT_FALSE(cda.GetSourceFileId().has_value());
|
||||
|
||||
cda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
|
||||
cda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
|
||||
cda.EnumerateFields([](panda_file::FieldDataAccessor &) { ASSERT_TRUE(false); });
|
||||
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
|
||||
ASSERT_FALSE(mda.IsExternal());
|
||||
ASSERT_EQ(mda.GetClassId(), class_id);
|
||||
ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(mda.GetNameId()).data, utf::CStringAsMutf8("main")),
|
||||
0);
|
||||
|
||||
panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
|
||||
ASSERT_EQ(pda.GetNumArgs(), 0U);
|
||||
ASSERT_EQ(pda.GetReturnType().GetId(), panda_file::Type::TypeId::VOID);
|
||||
|
||||
ASSERT_EQ(mda.GetAccessFlags(), ACC_STATIC);
|
||||
ASSERT_TRUE(mda.GetCodeId().has_value());
|
||||
|
||||
panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value());
|
||||
ASSERT_EQ(cdacc.GetNumVregs(), 0U);
|
||||
ASSERT_EQ(cdacc.GetNumArgs(), 0U);
|
||||
ASSERT_EQ(cdacc.GetCodeSize(), 1U);
|
||||
ASSERT_EQ(cdacc.GetTriesSize(), 0U);
|
||||
|
||||
ASSERT_FALSE(mda.GetRuntimeParamAnnotationId().has_value());
|
||||
ASSERT_FALSE(mda.GetParamAnnotationId().has_value());
|
||||
ASSERT_TRUE(mda.GetDebugInfoId().has_value());
|
||||
|
||||
panda_file::DebugInfoDataAccessor dda(*pf, mda.GetDebugInfoId().value());
|
||||
ASSERT_EQ(dda.GetLineStart(), 8U);
|
||||
ASSERT_EQ(dda.GetNumParams(), 0U);
|
||||
|
||||
mda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
mda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
});
|
||||
}
|
||||
|
||||
// Check R class
|
||||
{
|
||||
std::string descriptor;
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
ASSERT_FALSE(pf->IsExternal(class_id));
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
ASSERT_EQ(cda.GetSuperClassId().GetOffset(), 0U);
|
||||
ASSERT_EQ(cda.GetAccessFlags(), 0);
|
||||
ASSERT_EQ(cda.GetFieldsNumber(), 2U);
|
||||
ASSERT_EQ(cda.GetMethodsNumber(), 0U);
|
||||
ASSERT_EQ(cda.GetIfacesNumber(), 0U);
|
||||
|
||||
// We emit SET_FILE in debuginfo
|
||||
ASSERT_TRUE(cda.GetSourceFileId().has_value());
|
||||
|
||||
EXPECT_EQ(std::string(reinterpret_cast<const char *>(pf->GetStringData(cda.GetSourceFileId().value()).data)),
|
||||
source_filename);
|
||||
|
||||
cda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
|
||||
cda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
|
||||
struct FieldData {
|
||||
std::string name;
|
||||
panda_file::Type::TypeId type_id;
|
||||
uint32_t access_flags;
|
||||
};
|
||||
|
||||
std::vector<FieldData> fields {{"sf", panda_file::Type::TypeId::I32, ACC_STATIC},
|
||||
{"if", panda_file::Type::TypeId::I8, 0}};
|
||||
|
||||
size_t i = 0;
|
||||
cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) {
|
||||
ASSERT_FALSE(fda.IsExternal());
|
||||
ASSERT_EQ(fda.GetClassId(), class_id);
|
||||
ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(fda.GetNameId()).data,
|
||||
utf::CStringAsMutf8(fields[i].name.c_str())),
|
||||
0);
|
||||
|
||||
ASSERT_EQ(fda.GetType(), panda_file::Type(fields[i].type_id).GetFieldEncoding());
|
||||
ASSERT_EQ(fda.GetAccessFlags(), fields[i].access_flags);
|
||||
|
||||
fda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
fda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); });
|
||||
|
||||
++i;
|
||||
});
|
||||
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &) { ASSERT_TRUE(false); });
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t GetSpecialOpcode(uint32_t pc_inc, int32_t line_inc)
|
||||
{
|
||||
return (line_inc - panda_file::LineNumberProgramItem::LINE_BASE) +
|
||||
(pc_inc * panda_file::LineNumberProgramItem::LINE_RANGE) + panda_file::LineNumberProgramItem::OPCODE_BASE;
|
||||
}
|
||||
|
||||
TEST(emittertests, debuginfo)
|
||||
{
|
||||
Parser p;
|
||||
|
||||
auto source = R"(
|
||||
.function void main() {
|
||||
ldai.64 0 # line 3, pc 0
|
||||
# line 4
|
||||
# line 5
|
||||
# line 6
|
||||
# line 7
|
||||
# line 8
|
||||
# line 9
|
||||
# line 10
|
||||
# line 11
|
||||
# line 12
|
||||
# line 13
|
||||
# line 14
|
||||
ldai.64 1 # line 15, pc 9
|
||||
return.void # line 16, pc 18
|
||||
}
|
||||
)";
|
||||
|
||||
std::string source_filename = "source.pa";
|
||||
auto res = p.Parse(source, source_filename);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
|
||||
panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value());
|
||||
ASSERT_TRUE(mda.GetDebugInfoId().has_value());
|
||||
|
||||
panda_file::DebugInfoDataAccessor dda(*pf, mda.GetDebugInfoId().value());
|
||||
ASSERT_EQ(dda.GetLineStart(), 3U);
|
||||
ASSERT_EQ(dda.GetNumParams(), 0U);
|
||||
|
||||
const uint8_t *program = dda.GetLineNumberProgram();
|
||||
Span<const uint8_t> constant_pool = dda.GetConstantPool();
|
||||
|
||||
std::vector<uint8_t> opcodes {static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::SET_FILE),
|
||||
static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::ADVANCE_PC),
|
||||
static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::ADVANCE_LINE),
|
||||
GetSpecialOpcode(0, 0),
|
||||
GetSpecialOpcode(9, 1),
|
||||
static_cast<uint8_t>(panda_file::LineNumberProgramItem::Opcode::END_SEQUENCE)};
|
||||
|
||||
EXPECT_THAT(opcodes, ::testing::ElementsAreArray(program, opcodes.size()));
|
||||
|
||||
size_t size;
|
||||
bool is_full;
|
||||
size_t constant_pool_offset = 0;
|
||||
|
||||
uint32_t offset;
|
||||
|
||||
std::tie(offset, size, is_full) = leb128::DecodeUnsigned<uint32_t>(&constant_pool[constant_pool_offset]);
|
||||
constant_pool_offset += size;
|
||||
ASSERT_TRUE(is_full);
|
||||
EXPECT_EQ(
|
||||
std::string(reinterpret_cast<const char *>(pf->GetStringData(panda_file::File::EntityId(offset)).data)),
|
||||
source_filename);
|
||||
|
||||
uint32_t pc_inc;
|
||||
std::tie(pc_inc, size, is_full) = leb128::DecodeUnsigned<uint32_t>(&constant_pool[constant_pool_offset]);
|
||||
constant_pool_offset += size;
|
||||
ASSERT_TRUE(is_full);
|
||||
EXPECT_EQ(pc_inc, 9U);
|
||||
|
||||
int32_t line_inc;
|
||||
std::tie(line_inc, size, is_full) = leb128::DecodeSigned<int32_t>(&constant_pool[constant_pool_offset]);
|
||||
constant_pool_offset += size;
|
||||
ASSERT_TRUE(is_full);
|
||||
EXPECT_EQ(line_inc, 12);
|
||||
|
||||
EXPECT_EQ(constant_pool_offset, constant_pool.size());
|
||||
});
|
||||
}
|
||||
|
||||
TEST(emittertests, exceptions)
|
||||
{
|
||||
Parser p;
|
||||
|
||||
auto source = R"(
|
||||
.record Exception1 {}
|
||||
.record Exception2 {}
|
||||
|
||||
.function void main() {
|
||||
ldai.64 0
|
||||
try_begin:
|
||||
ldai.64 1
|
||||
ldai.64 2
|
||||
try_end:
|
||||
ldai.64 3
|
||||
catch_begin1:
|
||||
ldai.64 4
|
||||
catch_begin2:
|
||||
ldai.64 5
|
||||
catchall_begin:
|
||||
ldai.64 6
|
||||
|
||||
.catch Exception1, try_begin, try_end, catch_begin1
|
||||
.catch Exception2, try_begin, try_end, catch_begin2
|
||||
.catchall try_begin, try_end, catchall_begin
|
||||
}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
|
||||
panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value());
|
||||
ASSERT_EQ(cdacc.GetNumVregs(), 0U);
|
||||
ASSERT_EQ(cdacc.GetNumArgs(), 0U);
|
||||
ASSERT_EQ(cdacc.GetTriesSize(), 1);
|
||||
|
||||
cdacc.EnumerateTryBlocks([&](panda_file::CodeDataAccessor::TryBlock &try_block) {
|
||||
EXPECT_EQ(try_block.GetStartPc(), 9);
|
||||
EXPECT_EQ(try_block.GetLength(), 18);
|
||||
EXPECT_EQ(try_block.GetNumCatches(), 3);
|
||||
|
||||
struct CatchInfo {
|
||||
panda_file::File::EntityId type_id;
|
||||
uint32_t handler_pc;
|
||||
};
|
||||
|
||||
std::vector<CatchInfo> catch_infos {{pf->GetClassId(GetTypeDescriptor("Exception1", &descriptor)), 4 * 9},
|
||||
{pf->GetClassId(GetTypeDescriptor("Exception2", &descriptor)), 5 * 9},
|
||||
{panda_file::File::EntityId(), 6 * 9}};
|
||||
|
||||
size_t i = 0;
|
||||
try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
|
||||
auto idx = catch_block.GetTypeIdx();
|
||||
auto id = idx != panda_file::INVALID_INDEX ? pf->ResolveClassIndex(mda.GetMethodId(), idx)
|
||||
: panda_file::File::EntityId();
|
||||
EXPECT_EQ(id, catch_infos[i].type_id);
|
||||
EXPECT_EQ(catch_block.GetHandlerPc(), catch_infos[i].handler_pc);
|
||||
++i;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
TEST(emittertests, errors)
|
||||
{
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.record A {
|
||||
B b
|
||||
}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Field A.b has undefined type");
|
||||
}
|
||||
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.function void A.b() {}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Function A.b is bound to undefined record A");
|
||||
}
|
||||
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.function A b() {}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Function b has undefined return type");
|
||||
}
|
||||
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.function void a(b a0) {}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Argument 0 of function a has undefined type");
|
||||
}
|
||||
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.record A <external>
|
||||
.function void A.x() {}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Non-external function A.x is bound to external record");
|
||||
}
|
||||
|
||||
{
|
||||
Ins i;
|
||||
Function f("test_fuzz_imms", pandasm::extensions::Language::ECMASCRIPT);
|
||||
Program prog;
|
||||
i.opcode = Opcode::LDAI_64;
|
||||
i.imms.clear();
|
||||
f.ins.push_back(i);
|
||||
prog.function_table.emplace("test_fuzz_imms", std::move(f));
|
||||
|
||||
auto pf = AsmEmitter::Emit(prog);
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Internal error during emitting function: test_fuzz_imms");
|
||||
}
|
||||
|
||||
{
|
||||
Ins i;
|
||||
Function f("test_fuzz_regs", pandasm::extensions::Language::ECMASCRIPT);
|
||||
Program prog;
|
||||
i.opcode = Opcode::LDA;
|
||||
i.regs.clear();
|
||||
f.ins.push_back(i);
|
||||
prog.function_table.emplace("test_fuzz_regs", std::move(f));
|
||||
|
||||
auto pf = AsmEmitter::Emit(prog);
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Internal error during emitting function: test_fuzz_regs");
|
||||
}
|
||||
|
||||
{
|
||||
Ins i;
|
||||
Function f("test_fuzz_ids", pandasm::extensions::Language::ECMASCRIPT);
|
||||
Program prog;
|
||||
i.opcode = Opcode::LDA_STR;
|
||||
i.ids.push_back("testFuzz");
|
||||
f.ins.push_back(i);
|
||||
prog.function_table.emplace("test_fuzz_ids", std::move(f));
|
||||
prog.strings.insert("testFuz_");
|
||||
|
||||
auto pf = AsmEmitter::Emit(prog);
|
||||
ASSERT_EQ(pf, nullptr);
|
||||
ASSERT_EQ(AsmEmitter::GetLastError(), "Internal error during emitting function: test_fuzz_ids");
|
||||
}
|
||||
}
|
||||
|
||||
enum class ItemType { RECORD, FIELD, FUNCTION, PARAMETER };
|
||||
|
||||
std::string ItemTypeToString(ItemType item_type)
|
||||
{
|
||||
switch (item_type) {
|
||||
case ItemType::RECORD:
|
||||
return "record";
|
||||
case ItemType::FIELD:
|
||||
return "field";
|
||||
case ItemType::FUNCTION:
|
||||
return "function";
|
||||
case ItemType::PARAMETER:
|
||||
return "parameter";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return "";
|
||||
}
|
||||
|
||||
template <Value::Type type>
|
||||
auto GetAnnotationElementValue(size_t idx)
|
||||
{
|
||||
using T = ValueTypeHelperT<type>;
|
||||
|
||||
if constexpr (std::is_arithmetic_v<T>) {
|
||||
if constexpr (type == Value::Type::U1) {
|
||||
return static_cast<uint32_t>(idx == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
auto res = idx == 0 ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max();
|
||||
|
||||
if constexpr (type == Value::Type::I8) {
|
||||
return static_cast<int32_t>(res);
|
||||
}
|
||||
if constexpr (type == Value::Type::U8) {
|
||||
return static_cast<uint32_t>(res);
|
||||
}
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
return res * (idx == 0 ? 10 : 0.1);
|
||||
}
|
||||
|
||||
return res;
|
||||
} else {
|
||||
switch (type) {
|
||||
case Value::Type::STRING:
|
||||
return idx == 0 ? "123" : "456";
|
||||
case Value::Type::RECORD:
|
||||
return idx == 0 ? "A" : "B";
|
||||
case Value::Type::ENUM:
|
||||
return idx == 0 ? "E.E1" : "E.E2";
|
||||
case Value::Type::ANNOTATION:
|
||||
return idx == 0 ? "id_A" : "id_B";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(emittertests, language)
|
||||
{
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.function void foo() {}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
ASSERT_FALSE(cda.GetSourceLang());
|
||||
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { ASSERT_FALSE(mda.GetSourceLang()); });
|
||||
}
|
||||
}
|
||||
|
||||
TEST(emittertests, constructors)
|
||||
{
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.record R {}
|
||||
.function void R.foo(R a0) <ctor> {}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
|
||||
auto *name = utf::Mutf8AsCString(pf->GetStringData(mda.GetNameId()).data);
|
||||
ASSERT_STREQ(name, ".ctor");
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.record R {}
|
||||
.function void R.foo(R a0) <cctor> {}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
|
||||
auto *name = utf::Mutf8AsCString(pf->GetStringData(mda.GetNameId()).data);
|
||||
ASSERT_STREQ(name, ".cctor");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(emittertests, field_value)
|
||||
{
|
||||
Parser p;
|
||||
|
||||
auto source = R"(
|
||||
.record panda.String <external>
|
||||
|
||||
.record R {
|
||||
u1 f_u1 <value=1>
|
||||
i8 f_i8 <value=2>
|
||||
u8 f_u8 <value=128>
|
||||
i16 f_i16 <value=256>
|
||||
u16 f_u16 <value=32768>
|
||||
i32 f_i32 <value=65536>
|
||||
u32 f_u32 <value=2147483648>
|
||||
i64 f_i64 <value=4294967296>
|
||||
u64 f_u64 <value=9223372036854775808>
|
||||
f32 f_f32 <value=1.0>
|
||||
f64 f_f64 <value=2.0>
|
||||
panda.String f_str <value="str">
|
||||
}
|
||||
)";
|
||||
|
||||
struct FieldData {
|
||||
std::string name;
|
||||
panda_file::Type::TypeId type_id;
|
||||
std::variant<int32_t, uint32_t, int64_t, uint64_t, float, double, std::string> value;
|
||||
};
|
||||
|
||||
std::vector<FieldData> data {
|
||||
{"f_u1", panda_file::Type::TypeId::U1, static_cast<uint32_t>(1)},
|
||||
{"f_i8", panda_file::Type::TypeId::I8, static_cast<int32_t>(2)},
|
||||
{"f_u8", panda_file::Type::TypeId::U8, static_cast<uint32_t>(128)},
|
||||
{"f_i16", panda_file::Type::TypeId::I16, static_cast<int32_t>(256)},
|
||||
{"f_u16", panda_file::Type::TypeId::U16, static_cast<uint32_t>(32768)},
|
||||
{"f_i32", panda_file::Type::TypeId::I32, static_cast<int32_t>(65536)},
|
||||
{"f_u32", panda_file::Type::TypeId::U32, static_cast<uint32_t>(2147483648)},
|
||||
{"f_i64", panda_file::Type::TypeId::I64, static_cast<int64_t>(4294967296)},
|
||||
{"f_u64", panda_file::Type::TypeId::U64, static_cast<uint64_t>(9223372036854775808ULL)},
|
||||
{"f_f32", panda_file::Type::TypeId::F32, static_cast<float>(1.0)},
|
||||
{"f_f64", panda_file::Type::TypeId::F64, static_cast<double>(2.0)},
|
||||
{"f_str", panda_file::Type::TypeId::REFERENCE, "str"}};
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
ASSERT_FALSE(pf->IsExternal(class_id));
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
ASSERT_EQ(cda.GetFieldsNumber(), data.size());
|
||||
|
||||
auto panda_string_id = pf->GetClassId(GetTypeDescriptor("panda.String", &descriptor));
|
||||
|
||||
size_t idx = 0;
|
||||
cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) {
|
||||
const FieldData &field_data = data[idx];
|
||||
|
||||
ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(fda.GetNameId()).data,
|
||||
utf::CStringAsMutf8(field_data.name.c_str())),
|
||||
0);
|
||||
|
||||
panda_file::Type type(field_data.type_id);
|
||||
uint32_t type_value;
|
||||
if (type.IsReference()) {
|
||||
type_value = panda_string_id.GetOffset();
|
||||
} else {
|
||||
type_value = type.GetFieldEncoding();
|
||||
}
|
||||
|
||||
ASSERT_EQ(fda.GetType(), type_value);
|
||||
|
||||
switch (field_data.type_id) {
|
||||
case panda_file::Type::TypeId::U1: {
|
||||
auto result = fda.GetValue<uint8_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<uint32_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::I8: {
|
||||
auto result = fda.GetValue<int8_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<int32_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::U8: {
|
||||
auto result = fda.GetValue<uint8_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<uint32_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::I16: {
|
||||
auto result = fda.GetValue<int16_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<int32_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::U16: {
|
||||
auto result = fda.GetValue<uint16_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<uint32_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::I32: {
|
||||
auto result = fda.GetValue<int32_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<int32_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::U32: {
|
||||
auto result = fda.GetValue<uint32_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<uint32_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::I64: {
|
||||
auto result = fda.GetValue<int64_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<int64_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::U64: {
|
||||
auto result = fda.GetValue<uint64_t>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<uint64_t>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::F32: {
|
||||
auto result = fda.GetValue<float>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<float>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::F64: {
|
||||
auto result = fda.GetValue<double>();
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(result.value(), std::get<double>(field_data.value));
|
||||
break;
|
||||
}
|
||||
case panda_file::Type::TypeId::REFERENCE: {
|
||||
auto result = fda.GetValue<uint32_t>();
|
||||
ASSERT_TRUE(result);
|
||||
|
||||
panda_file::File::EntityId string_id(result.value());
|
||||
auto val = std::get<std::string>(field_data.value);
|
||||
|
||||
ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(string_id).data, utf::CStringAsMutf8(val.c_str())),
|
||||
0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++idx;
|
||||
});
|
||||
}
|
||||
|
||||
TEST(emittertests, tagged_in_func_decl)
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.function any foo(any a0) <noimpl>
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
size_t num_methods = 0;
|
||||
const auto tagged = panda_file::Type(panda_file::Type::TypeId::TAGGED);
|
||||
cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
|
||||
panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
|
||||
ASSERT_EQ(tagged, pda.GetReturnType());
|
||||
ASSERT_EQ(1, pda.GetNumArgs());
|
||||
ASSERT_EQ(tagged, pda.GetArgType(0));
|
||||
|
||||
++num_methods;
|
||||
});
|
||||
ASSERT_EQ(1, num_methods);
|
||||
}
|
||||
|
||||
TEST(emittertests, tagged_in_field_decl)
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.record Test {
|
||||
any foo
|
||||
}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("Test", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
size_t num_fields = 0;
|
||||
const auto tagged = panda_file::Type(panda_file::Type::TypeId::TAGGED);
|
||||
cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) {
|
||||
uint32_t type = fda.GetType();
|
||||
ASSERT_EQ(tagged.GetFieldEncoding(), type);
|
||||
|
||||
++num_fields;
|
||||
});
|
||||
ASSERT_EQ(1, num_fields);
|
||||
}
|
||||
|
||||
TEST(emittertests, get_GLOBAL_lang_for_JS_func)
|
||||
{
|
||||
Parser p;
|
||||
auto source = R"(
|
||||
.language ECMAScript
|
||||
|
||||
.function any main() {
|
||||
return.dyn
|
||||
}
|
||||
)";
|
||||
|
||||
auto res = p.Parse(source);
|
||||
ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
|
||||
auto pf = AsmEmitter::Emit(res.Value());
|
||||
ASSERT_NE(pf, nullptr);
|
||||
|
||||
std::string descriptor;
|
||||
|
||||
auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor));
|
||||
ASSERT_TRUE(class_id.IsValid());
|
||||
|
||||
panda_file::ClassDataAccessor cda(*pf, class_id);
|
||||
|
||||
ASSERT_TRUE(cda.GetSourceLang().has_value());
|
||||
ASSERT_EQ(cda.GetSourceLang(), panda_file::SourceLang::ECMASCRIPT);
|
||||
}
|
||||
|
||||
} // namespace panda::test
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "../define.h"
|
||||
#include "../lexer.h"
|
||||
|
||||
namespace panda::test {
|
||||
|
||||
using namespace panda::pandasm;
|
||||
|
||||
TEST(lexertests, test1)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "mov v1, v2";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test2)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "ldai 1";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test3)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "movi\nlda v2 v10 mov v2";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[4].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[5].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test4)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "jmp Iasdfsadkfjhasifhsaiuhdacoisjdaociewhasdasdfkjasdfhjksadhfkhsakdfjhksajhdkfjhskhdfkjahhjdskaj";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test5)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "call.short 1111, 1";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test6)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "jle v1 met";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test7)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "label:";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test8)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = ",";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test9)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = ",:{}()<>=";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "DEL_COLON") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_BRACE_L") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "DEL_BRACE_R") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[4].type), "DEL_BRACKET_L") << "DEL_BRACKET_L expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[5].type), "DEL_BRACKET_R") << "DEL_BRACKET_R expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[6].type), "DEL_LT") << "DEL_LT expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[7].type), "DEL_GT") << "DEL_GT expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[8].type), "DEL_EQ") << "DEL_EQ expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test11)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s =
|
||||
"i64.to.f32 alsdhashdjskhfka "
|
||||
"shdkfhkasdhfkhsakdhfkshkfhskahlfkjsdfkjadskhfkshadkhfsdakhfksahdkfaksdfkhaskldhkfashdlfkjhasdkjfhklasjhdfklhsa"
|
||||
"fhska";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test12)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = ".function asd(u32){}";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "KEYWORD") << "KEYWORD expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, string_literal)
|
||||
{
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "\"123";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER);
|
||||
}
|
||||
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "\"123\\\"";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER);
|
||||
}
|
||||
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "\" a b \\ c d \"";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
ASSERT_EQ(tok.first.size(), 1U);
|
||||
ASSERT_EQ(tok.first[0].type, Token::Type::ID_STRING);
|
||||
ASSERT_EQ(tok.first[0].bound_left, 0U);
|
||||
ASSERT_EQ(tok.first[0].bound_right, s.length());
|
||||
}
|
||||
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "\"abcd\"1234";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
ASSERT_EQ(tok.first.size(), 2U);
|
||||
ASSERT_EQ(tok.first[0].type, Token::Type::ID_STRING);
|
||||
ASSERT_EQ(tok.first[0].bound_left, 0U);
|
||||
ASSERT_EQ(tok.first[0].bound_right, s.find('1'));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(lexertests, array_type)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "i32[]";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
ASSERT_EQ(tok.first.size(), 3U);
|
||||
ASSERT_EQ(tok.first[0].type, Token::Type::ID);
|
||||
ASSERT_EQ(tok.first[1].type, Token::Type::DEL_SQUARE_BRACKET_L);
|
||||
ASSERT_EQ(tok.first[2].type, Token::Type::DEL_SQUARE_BRACKET_R);
|
||||
}
|
||||
|
||||
} // namespace panda::test
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "mangling.h"
|
||||
#include "assembly-function.h"
|
||||
#include "extensions/extensions.h"
|
||||
|
||||
namespace panda::test {
|
||||
|
||||
using namespace panda::pandasm;
|
||||
|
||||
TEST(mangling_tests, MangleFunctionName)
|
||||
{
|
||||
std::vector<Function::Parameter> params;
|
||||
extensions::Language language {extensions::Language::PANDA_ASSEMBLY};
|
||||
params.emplace_back(Type {"type1", 0}, language);
|
||||
params.emplace_back(Type {"type2", 0}, language);
|
||||
params.emplace_back(Type {"type3", 0}, language);
|
||||
|
||||
auto return_type = Type("type4", 0);
|
||||
|
||||
std::string name = "Asm.main";
|
||||
ASSERT_EQ(MangleFunctionName(name, std::move(params), return_type), "Asm.main:type1;type2;type3;type4;");
|
||||
}
|
||||
|
||||
TEST(mangling_tests, DeMangleFunctionName)
|
||||
{
|
||||
std::string name = "Asm.main:type1;type2;type3;type4;";
|
||||
ASSERT_EQ(DeMangleName(name), "Asm.main");
|
||||
}
|
||||
|
||||
} // namespace panda::test
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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 PANDA_ASSEMBLER_UTILS_NUMBER_UTILS_H_
|
||||
#define PANDA_ASSEMBLER_UTILS_NUMBER_UTILS_H_
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
constexpr size_t HEX_BASE = 16;
|
||||
|
||||
constexpr size_t DEC_BASE = 10;
|
||||
|
||||
constexpr size_t OCT_BASE = 8;
|
||||
|
||||
constexpr size_t BIN_BASE = 2;
|
||||
|
||||
constexpr size_t MAX_DWORD = 65536;
|
||||
|
||||
inline bool ValidateHexInteger(std::string_view p)
|
||||
{
|
||||
std::string_view token = p;
|
||||
token.remove_prefix(2U);
|
||||
|
||||
for (auto i : token) {
|
||||
if (!((i >= '0' && i <= '9') || (i >= 'A' && i <= 'F') || (i >= 'a' && i <= 'f'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ValidateBinInteger(std::string_view p)
|
||||
{
|
||||
std::string_view token = p;
|
||||
token.remove_prefix(2U);
|
||||
if (token.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (auto i : token) {
|
||||
if (!(i == '0' || i == '1')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ValidateOctalInteger(std::string_view p)
|
||||
{
|
||||
std::string_view token = p;
|
||||
token.remove_prefix(1);
|
||||
|
||||
for (auto i : token) {
|
||||
if (!(i >= '0' && i <= '7')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ValidateInteger(std::string_view p)
|
||||
{
|
||||
std::string_view token = p;
|
||||
|
||||
if (token.back() == '-' || token.back() == '+' || token.back() == 'x' || token == ".") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (token[0] == '-' || token[0] == '+') {
|
||||
token.remove_prefix(1);
|
||||
}
|
||||
|
||||
if (token[0] == '0' && token.size() > 1 && token.find('.') == std::string::npos) {
|
||||
if (token[1] == 'x') {
|
||||
return ValidateHexInteger(token);
|
||||
}
|
||||
|
||||
if (token[1] == 'b') {
|
||||
return ValidateBinInteger(token);
|
||||
}
|
||||
|
||||
if (token[1] >= '0' && token[1] <= '9' && token.find('e') == std::string::npos) {
|
||||
return ValidateOctalInteger(token);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i : token) {
|
||||
if (!(i >= '0' && i <= '9')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline int64_t IntegerNumber(std::string_view p)
|
||||
{
|
||||
constexpr size_t GENERAL_SHIFT = 2;
|
||||
|
||||
// expects a valid number
|
||||
if (p.size() == 1) {
|
||||
return p[0] - '0';
|
||||
}
|
||||
|
||||
size_t minus_shift = 0;
|
||||
if (p[0] == '-') {
|
||||
minus_shift++;
|
||||
}
|
||||
|
||||
if (p[minus_shift + 1] == 'b') {
|
||||
p.remove_prefix(GENERAL_SHIFT + minus_shift);
|
||||
return std::strtoull(p.data(), nullptr, BIN_BASE) * (minus_shift == 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
if (p[minus_shift + 1] == 'x') {
|
||||
return std::strtoull(p.data(), nullptr, HEX_BASE);
|
||||
}
|
||||
|
||||
if (p[minus_shift] == '0') {
|
||||
return std::strtoull(p.data(), nullptr, OCT_BASE);
|
||||
}
|
||||
|
||||
return std::strtoull(p.data(), nullptr, DEC_BASE);
|
||||
}
|
||||
|
||||
inline bool ValidateFloat(std::string_view p)
|
||||
{
|
||||
std::string_view token = p;
|
||||
|
||||
if (ValidateInteger(token)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (token[0] == '-' || token[0] == '+') {
|
||||
token.remove_prefix(1);
|
||||
}
|
||||
|
||||
bool dot = false;
|
||||
bool exp = false;
|
||||
bool nowexp = false;
|
||||
|
||||
for (auto i : token) {
|
||||
if (nowexp && (i == '-' || i == '+')) {
|
||||
nowexp = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nowexp) {
|
||||
nowexp = false;
|
||||
}
|
||||
|
||||
if (i == '.' && !exp && !dot) {
|
||||
dot = true;
|
||||
} else if (!exp && i == 'e') {
|
||||
nowexp = true;
|
||||
exp = true;
|
||||
} else if (!(i >= '0' && i <= '9')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !nowexp;
|
||||
}
|
||||
|
||||
inline double FloatNumber(std::string_view p)
|
||||
{
|
||||
constexpr size_t GENERAL_SHIFT = 2;
|
||||
// expects a valid number
|
||||
if (p.size() > GENERAL_SHIFT && p.substr(0, GENERAL_SHIFT) == "0x") { // hex literal
|
||||
char *end = nullptr;
|
||||
return bit_cast<double>(strtoull(p.data(), &end, 0));
|
||||
}
|
||||
return std::strtold(std::string(p.data(), p.length()).c_str(), nullptr);
|
||||
}
|
||||
|
||||
inline size_t ToNumber(std::string_view p)
|
||||
{
|
||||
size_t sum = 0;
|
||||
|
||||
for (char i : p) {
|
||||
if (isdigit(i) != 0) {
|
||||
sum = sum * DEC_BASE + (i - '0');
|
||||
} else {
|
||||
return MAX_DWORD;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_UTILS_NUMBER_UTILS_H_
|
||||
@@ -0,0 +1,179 @@
|
||||
# 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.
|
||||
|
||||
option(PANDA_ENABLE_CLANG_TIDY "Enable clang-tidy checks during compilation" true)
|
||||
|
||||
# There seems to be a bug in either clang-tidy or CMake:
|
||||
# When clang/gcc is used for cross-compilation, it is ran on host and use definitions and options for host
|
||||
# For example for arm32 cross-compilation Clang-Tidy:
|
||||
# - don't know about -march=armv7-a
|
||||
# - believes that size of pointer is 64 instead of 32 for aarch32
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(PANDA_ENABLE_CLANG_TIDY false)
|
||||
endif()
|
||||
|
||||
if(PANDA_TARGET_MACOS)
|
||||
set(PANDA_ENABLE_CLANG_TIDY false)
|
||||
endif()
|
||||
|
||||
if(PANDA_ENABLE_CLANG_TIDY)
|
||||
# Currently we fix a certain version of clang-tidy to avoid unstable linting,
|
||||
# which may occur if different versions of the tools are used by developers.
|
||||
set(panda_clang_tidy "clang-tidy-9")
|
||||
|
||||
# Require clang-tidy
|
||||
find_program(
|
||||
CLANG_TIDY
|
||||
NAMES ${panda_clang_tidy}
|
||||
DOC "Path to clang-tidy executable")
|
||||
if(NOT CLANG_TIDY)
|
||||
message(FATAL_ERROR "clang-tidy not found, but requested for build. Use -DPANDA_ENABLE_CLANG_TIDY=false to suppress.")
|
||||
endif()
|
||||
|
||||
unset(panda_clang_tidy)
|
||||
|
||||
message(STATUS "clang-tidy found: ${CLANG_TIDY}")
|
||||
# NB! Even if config is malformed, clang-tidy -dump-config returns 0 on failure.
|
||||
# Hence we check for ERROR_VARIABLE instead of RESULT_VARIABLE.
|
||||
execute_process(
|
||||
COMMAND ${CLANG_TIDY} -dump-config
|
||||
WORKING_DIRECTORY ${PANDA_ROOT}
|
||||
ERROR_VARIABLE dump_config_stderr)
|
||||
if (dump_config_stderr AND NOT "${dump_config_stderr}" STREQUAL "")
|
||||
message(FATAL_ERROR "${dump_config_stderr}")
|
||||
endif()
|
||||
# See https://gitlab.kitware.com/cmake/cmake/issues/18926.
|
||||
# Create a preprocessor definition that depends on .clang-tidy content so
|
||||
# the compile command will change when .clang-tidy changes. This ensures
|
||||
# that a subsequent build re-runs clang-tidy on all sources even if they
|
||||
# do not otherwise need to be recompiled. Nothing actually uses this
|
||||
# definition. We add it to targets on which we run clang-tidy just to
|
||||
# get the build dependency on the .clang-tidy file.
|
||||
file(SHA1 ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1)
|
||||
set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}")
|
||||
unset(clang_tidy_sha1)
|
||||
configure_file(${PANDA_ROOT}/.clang-tidy ${PANDA_BINARY_ROOT}/.clang-tidy COPYONLY)
|
||||
endif()
|
||||
|
||||
# Add a target to clang-tidy checks.
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# panda_add_to_clang_tidy(TARGET target_name
|
||||
# CHECKS
|
||||
# "-check-to-be-disabled"
|
||||
# "-glob-to-be-disabled-*"
|
||||
# "check-to-be-enabled"
|
||||
# "glob-to-be-enabled-*"
|
||||
# )
|
||||
#
|
||||
# This function makes target_name to be co-compiled with clang-tidy.
|
||||
# The list of CHECKS allows to pass per-target checks in additions to
|
||||
# global ones (see below). CHECKS follow clang-tidy syntax of checks.
|
||||
# By default all checks are enabled globally, so the most reasonable use
|
||||
# case for CHECKS is to pass checks to be suppressed.
|
||||
|
||||
# NB! Important caveats:
|
||||
# * We use permissive policy for checks, i.e. everything is enabled by default,
|
||||
# then exceptions are suppressed explicitly.
|
||||
# * We maintain the list of global exceptions in this function (not in .clang-tidy)
|
||||
# because of its syntax limitations (in particular, all checks should be passed
|
||||
# as a single string in YAML, which is not readable).
|
||||
# * -header-filter is set to check only headers of the target_name. It is supposed
|
||||
# that each components is responsible for QA'ing only its code base.
|
||||
function(panda_add_to_clang_tidy)
|
||||
if(NOT PANDA_ENABLE_CLANG_TIDY)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(prefix ARG)
|
||||
set(noValues)
|
||||
set(singleValues TARGET)
|
||||
set(multiValues CHECKS)
|
||||
|
||||
cmake_parse_arguments(${prefix}
|
||||
"${noValues}"
|
||||
"${singleValues}"
|
||||
"${multiValues}"
|
||||
${ARGN})
|
||||
|
||||
set(clang_tidy_params
|
||||
"${CLANG_TIDY}"
|
||||
"-config="
|
||||
"-format-style=file"
|
||||
"-header-filter='^(${CMAKE_SOURCE_DIR}|${CMAKE_BINARY_DIR}).*/(assembler|compiler|debugger|libpandabase|libpandafile|runtime|class2panda)/.*'"
|
||||
"-p='${PANDA_BINARY_ROOT}'"
|
||||
)
|
||||
|
||||
set(clang_tidy_default_exceptions
|
||||
# aliases for other checks(here full list: https://clang.llvm.org/extra/clang-tidy/checks/list.html):
|
||||
"-hicpp-braces-around-statements" # alias for readability-braces-around-statements
|
||||
"-google-readability-braces-around-statements" # alias for readability-braces-around-statements
|
||||
"-google-readability-function-size" # alias for readability-function-size
|
||||
"-hicpp-explicit-conversions" # alias for google-explicit-constructor
|
||||
"-hicpp-function-size" # alias for readability-function-size
|
||||
"-hicpp-no-array-decay" # alias for cppcoreguidelines-pro-bounds-array-to-pointer-decay
|
||||
"-hicpp-avoid-c-arrays" # alias for modernize-avoid-c-arrays
|
||||
"-cppcoreguidelines-avoid-c-arrays" # alias for modernize-avoid-c-arrays
|
||||
"-cppcoreguidelines-avoid-magic-numbers" # alias for readability-magic-numbers
|
||||
"-cppcoreguidelines-non-private-member-variables-in-classes" # alias for misc-non-private-member-variables-in-classes
|
||||
"-cert-dcl03-c" # alias for misc-static-assert
|
||||
"-hicpp-static-assert" # alias for misc-static-assert
|
||||
"-hicpp-no-malloc" # alias for cppcoreguidelines-no-malloc
|
||||
"-hicpp-vararg" # alias for cppcoreguidelines-pro-type-vararg
|
||||
"-hicpp-member-init" # alias for cppcoreguidelines-pro-type-member-init
|
||||
"-hicpp-move-const-arg" # alias for performance-move-const-arg
|
||||
# explicitly disabled checks
|
||||
"-bugprone-macro-parentheses" # disabled because it is hard to write macroses with types with it
|
||||
"-llvm-header-guard" # disabled because of incorrect root prefix
|
||||
"-llvm-include-order" # disabled because conflicts with the clang-format
|
||||
"-readability-identifier-naming" # disabled because we will use little-hump-style
|
||||
"google-runtime-references" # disabled to use non-const references
|
||||
"-fuchsia-trailing-return" # disabled because we have a lot of false positives and it is stylistic check
|
||||
"-fuchsia-default-arguments-calls" # disabled because we use functions with default arguments a lot
|
||||
"-fuchsia-default-arguments-declarations" # disabled because we use functions with default arguments a lot
|
||||
"-modernize-use-trailing-return-type" # disabled as a stylistic check
|
||||
"-clang-analyzer-optin.cplusplus.UninitializedObject" # disabled due to instability on clang-9 and clang-10
|
||||
"-readability-static-accessed-through-instance"
|
||||
"-readability-convert-member-functions-to-static"
|
||||
"-bugprone-sizeof-expression"
|
||||
"-bugprone-branch-clone"
|
||||
"-cppcoreguidelines-owning-memory"
|
||||
"-cppcoreguidelines-pro-bounds-array-to-pointer-decay"
|
||||
"-cppcoreguidelines-pro-bounds-constant-array-index"
|
||||
"-cppcoreguidelines-pro-type-const-cast"
|
||||
"-cppcoreguidelines-pro-type-reinterpret-cast"
|
||||
"-cppcoreguidelines-pro-type-static-cast-downcast"
|
||||
"-fuchsia-default-arguments"
|
||||
"-fuchsia-overloaded-operator"
|
||||
"-modernize-use-nodiscard"
|
||||
"-cert-dcl50-cpp" # ailas for cppcoreguidelines-pro-type-vararg
|
||||
# candidates for removal:
|
||||
"-hicpp-noexcept-move" # For some reason become failed in DEFAULT_MOVE_SEMANTIC
|
||||
"-performance-noexcept-move-constructor" # Same as above
|
||||
)
|
||||
# NB! Replace with list(JOIN ...) after switching to CMake 3.12+
|
||||
string(REPLACE ";" "," default_exceptions "${clang_tidy_default_exceptions}")
|
||||
|
||||
set(clang_tidy_checks "-checks=*,${default_exceptions}")
|
||||
|
||||
if(DEFINED ARG_CHECKS)
|
||||
# NB! Replace with list(JOIN ...) after switching to CMake 3.12+
|
||||
string(REPLACE ";" "," custom_checks "${ARG_CHECKS}")
|
||||
set(clang_tidy_checks "${clang_tidy_checks},${custom_checks}")
|
||||
endif()
|
||||
|
||||
list(APPEND clang_tidy_params "${clang_tidy_checks}")
|
||||
|
||||
set_target_properties(${ARG_TARGET} PROPERTIES CXX_CLANG_TIDY "${clang_tidy_params}")
|
||||
endfunction()
|
||||
@@ -0,0 +1,108 @@
|
||||
# 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.
|
||||
|
||||
# Currently we fix a certain version of clang-format to avoid unstable linting,
|
||||
# which may occur if different versions of the tools are used by developers.
|
||||
set(PANDA_CLANG_FORMAT "clang-format-9")
|
||||
|
||||
# Require clang-format
|
||||
find_program(
|
||||
CLANG_FORMAT
|
||||
NAMES "${PANDA_CLANG_FORMAT}"
|
||||
DOC "Path to clang-format executable"
|
||||
)
|
||||
if(NOT CLANG_FORMAT)
|
||||
message(WARNING "Clang-format not found.")
|
||||
else()
|
||||
message(STATUS "clang-format found: ${CLANG_FORMAT}")
|
||||
endif()
|
||||
|
||||
# Function to add targets for clang_format, clang_force_format
|
||||
function(add_check_style dir)
|
||||
file(GLOB_RECURSE dir_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${dir}/*.cpp ${dir}/*.cc)
|
||||
file(GLOB_RECURSE dir_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${dir}/*.h)
|
||||
|
||||
if (CLANG_FORMAT)
|
||||
if(TARGET clang_format)
|
||||
else()
|
||||
add_custom_target(clang_format)
|
||||
endif()
|
||||
if(TARGET clang_force_format)
|
||||
else()
|
||||
add_custom_target(clang_force_format)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET check_concurrency_format)
|
||||
add_custom_target(check_concurrency_format)
|
||||
endif()
|
||||
|
||||
foreach(src ${dir_sources})
|
||||
get_filename_component(source ${src} ABSOLUTE)
|
||||
file(RELATIVE_PATH src ${PANDA_ROOT} ${source})
|
||||
STRING(REGEX REPLACE "/" "_" src ${src})
|
||||
if (CLANG_FORMAT)
|
||||
add_clang_format(${source} ${src})
|
||||
add_clang_force_format(${source} ${src})
|
||||
endif()
|
||||
add_check_concurrency_format(${source} ${src})
|
||||
endforeach()
|
||||
|
||||
# Also add format-target for headers
|
||||
foreach(src ${dir_headers})
|
||||
get_filename_component(source ${src} ABSOLUTE)
|
||||
file(RELATIVE_PATH src ${PANDA_ROOT} ${source})
|
||||
STRING(REGEX REPLACE "/" "_" src ${src})
|
||||
if (CLANG_FORMAT)
|
||||
add_clang_format(${source} ${src})
|
||||
add_clang_force_format(${source} ${src})
|
||||
add_dependencies(clang_format clang_format_${src})
|
||||
add_dependencies(clang_force_format clang_force_format_${src})
|
||||
endif()
|
||||
add_check_concurrency_format(${source} ${src})
|
||||
add_dependencies(check_concurrency_format check_concurrency_format_${src})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Function to check through clang-format
|
||||
function(add_clang_format src tgt)
|
||||
if (TARGET clang_format_${tgt})
|
||||
return()
|
||||
endif()
|
||||
add_custom_target(clang_format_${tgt}
|
||||
COMMAND ${PANDA_ROOT}/scripts/run-clang-format ${PANDA_CLANG_FORMAT} ${src})
|
||||
add_dependencies(clang_format clang_format_${tgt})
|
||||
endfunction()
|
||||
|
||||
# Function to check correct usage of std primitives.
|
||||
function(add_check_concurrency_format src tgt)
|
||||
set(CHECK_CONCURRENCY_FORMAT "${PANDA_ROOT}/scripts/run-check-concurrency-format.sh")
|
||||
|
||||
if (NOT TARGET check_concurrency_format_${tgt})
|
||||
add_custom_target(check_concurrency_format_${tgt}
|
||||
COMMAND ${CHECK_CONCURRENCY_FORMAT} ${src}
|
||||
)
|
||||
add_dependencies(check_concurrency_format check_concurrency_format_${tgt})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to force style through clang-format
|
||||
function(add_clang_force_format src tgt)
|
||||
if (NOT TARGET clang_force_format_${tgt})
|
||||
add_custom_target(clang_force_format_${tgt}
|
||||
COMMAND ${CLANG_FORMAT} -i -style=file ${src}
|
||||
)
|
||||
add_dependencies(clang_force_format clang_force_format_${tgt})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
# 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.
|
||||
# Convenience functions for testing Panda.
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/PandaCmakeFunctions.cmake)
|
||||
|
||||
function(common_add_gtest)
|
||||
set(prefix ARG)
|
||||
set(noValues CONTAINS_MAIN NO_CORES RAPIDCHECK_ON USE_CATCH2)
|
||||
set(singleValues NAME OUTPUT_DIRECTORY ENCLOSING_TARGET TSAN_EXTRA_OPTIONS PANDA_STD_LIB ARK_BOOTCLASSPATH)
|
||||
set(multiValues SOURCES INCLUDE_DIRS LIBRARIES SANITIZERS)
|
||||
|
||||
cmake_parse_arguments(${prefix}
|
||||
"${noValues}"
|
||||
"${singleValues}"
|
||||
"${multiValues}"
|
||||
${ARGN})
|
||||
|
||||
if (ARG_RAPIDCHECK_ON AND DEFINED DONT_USE_RAPIDCHECK)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARG_ENCLOSING_TARGET)
|
||||
message(FATAL_ERROR "Enclosing target is not defined")
|
||||
endif()
|
||||
if (NOT DEFINED ARG_OUTPUT_DIRECTORY)
|
||||
message(FATAL_ERROR "OUTPUT_DIRECTORY is not defined")
|
||||
endif()
|
||||
|
||||
if(ARG_USE_CATCH2 AND NOT ARG_CONTAINS_MAIN)
|
||||
set(ARG_SOURCES ${ARG_SOURCES} ${PANDA_ROOT}/third_party/rapidcheck/test/main.cpp)
|
||||
endif()
|
||||
|
||||
if (ARG_RAPIDCHECK_ON)
|
||||
panda_add_executable(${ARG_NAME} RAPIDCHECK_ON ${ARG_SOURCES})
|
||||
set_target_properties(${ARG_NAME} PROPERTIES LINK_FLAGS "-frtti -fexceptions")
|
||||
target_compile_definitions(${ARG_NAME} PRIVATE PANDA_RAPIDCHECK)
|
||||
target_compile_options(${ARG_NAME} PRIVATE "-frtti" "-fexceptions" "-fPIC")
|
||||
target_compile_definitions(${ARG_NAME} PUBLIC PANDA_RAPIDCHECK)
|
||||
else()
|
||||
panda_add_executable(${ARG_NAME} ${ARG_SOURCES})
|
||||
endif()
|
||||
|
||||
if (ARG_USE_CATCH2)
|
||||
target_compile_definitions(${ARG_NAME} PUBLIC PANDA_CATCH2)
|
||||
else()
|
||||
target_compile_definitions(${ARG_NAME} PUBLIC PANDA_GTEST)
|
||||
endif()
|
||||
|
||||
if(PANDA_CI_TESTING_MODE STREQUAL "Nightly")
|
||||
target_compile_definitions(${ARG_NAME} PUBLIC PANDA_NIGHTLY_TEST_ON)
|
||||
endif()
|
||||
# By default tests are just built, running is available either via an
|
||||
# umbrella target or via `ctest -R ...`. But one can always do something
|
||||
# like this if really needed:
|
||||
# add_custom_target(${ARG_NAME}_run
|
||||
# COMMENT "Run ${ARG_NAME}"
|
||||
# COMMAND ${CMAKE_CTEST_COMMAND}
|
||||
# DEPENDS ${ARG_NAME})
|
||||
if (ARG_USE_CATCH2)
|
||||
foreach(include_dir ${ARG_INCLUDE_DIRS} ${PANDA_ROOT}/third_party/rapidcheck/include)
|
||||
target_include_directories(${ARG_NAME} PUBLIC ${include_dir})
|
||||
endforeach()
|
||||
else()
|
||||
foreach(include_dir ${ARG_INCLUDE_DIRS} ${PANDA_THIRD_PARTY_SOURCES_DIR}/googletest/googlemock/include)
|
||||
target_include_directories(${ARG_NAME} PUBLIC ${include_dir})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (NOT ARG_USE_CATCH2)
|
||||
if (ARG_CONTAINS_MAIN)
|
||||
target_link_libraries(${ARG_NAME} gtest)
|
||||
else()
|
||||
target_link_libraries(${ARG_NAME} gtest_main)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT (PANDA_TARGET_MOBILE OR PANDA_TARGET_OHOS))
|
||||
target_link_libraries(${ARG_NAME} pthread)
|
||||
endif()
|
||||
target_link_libraries(${ARG_NAME} ${ARG_LIBRARIES})
|
||||
add_dependencies(${ARG_ENCLOSING_TARGET} ${ARG_NAME})
|
||||
|
||||
if (ARG_RAPIDCHECK_ON)
|
||||
target_link_libraries(${ARG_NAME} rapidcheck)
|
||||
target_link_libraries(${ARG_NAME} rapidcheck_catch)
|
||||
target_link_libraries(${ARG_NAME} rapidcheck_gtest)
|
||||
target_link_libraries(${ARG_NAME} rapidcheck_gmock)
|
||||
add_dependencies(${ARG_NAME} rapidcheck)
|
||||
endif()
|
||||
|
||||
panda_add_sanitizers(TARGET ${ARG_NAME} SANITIZERS ${ARG_SANITIZERS})
|
||||
|
||||
set(prlimit_prefix "")
|
||||
if (ARG_NO_CORES)
|
||||
set(prlimit_prefix prlimit --core=0)
|
||||
endif()
|
||||
set_target_properties(${ARG_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}")
|
||||
|
||||
set(tsan_options "")
|
||||
if ("thread" IN_LIST PANDA_SANITIZERS_LIST)
|
||||
if (DEFINED ENV{TSAN_OPTIONS})
|
||||
set(tsan_options "TSAN_OPTIONS=$ENV{TSAN_OPTIONS},${ARG_TSAN_EXTRA_OPTIONS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Yes, this is hardcoded. No, do not ask for an option. Go and fix your tests.
|
||||
if (PANDA_CI_TESTING_MODE STREQUAL "Nightly")
|
||||
set(timeout_prefix timeout --preserve-status --signal=USR1 --kill-after=10s 40m)
|
||||
else ()
|
||||
set(timeout_prefix timeout --preserve-status --signal=USR1 --kill-after=10s 20m)
|
||||
endif()
|
||||
|
||||
if (ARG_RAPIDCHECK_ON)
|
||||
add_custom_target(${ARG_NAME}_rapidcheck_tests
|
||||
COMMAND ${tsan_options} ${prlimit_prefix} ${timeout_prefix}
|
||||
${PANDA_RUN_PREFIX} "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}"
|
||||
DEPENDS ${ARG_ENCLOSING_TARGET}
|
||||
)
|
||||
add_dependencies(gtests ${ARG_NAME}_rapidcheck_tests)
|
||||
else()
|
||||
set(PANDA_STD_LIB "")
|
||||
if (DEFINED ARG_PANDA_STD_LIB)
|
||||
set(PANDA_STD_LIB "PANDA_STD_LIB=${ARG_PANDA_STD_LIB}")
|
||||
endif()
|
||||
set(ARK_BOOTCLASSPATH "")
|
||||
if (DEFINED ARG_ARK_BOOTCLASSPATH)
|
||||
set(ARK_BOOTCLASSPATH "ARK_BOOTCLASSPATH=${ARG_ARK_BOOTCLASSPATH}")
|
||||
endif()
|
||||
add_custom_target(${ARG_NAME}_gtests
|
||||
COMMAND ${PANDA_STD_LIB} ${ARK_BOOTCLASSPATH}
|
||||
${tsan_options} ${prlimit_prefix} ${timeout_prefix}
|
||||
${PANDA_RUN_PREFIX} "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}"
|
||||
--gtest_shuffle --gtest_death_test_style=threadsafe
|
||||
DEPENDS ${ARG_ENCLOSING_TARGET}
|
||||
)
|
||||
add_dependencies(gtests ${ARG_NAME}_gtests)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,214 @@
|
||||
# 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.
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
set(PANDA_TARGET_LINUX 1)
|
||||
set(PANDA_TARGET_UNIX 1)
|
||||
if (NOT PANDA_ENABLE_ADDRESS_SANITIZER)
|
||||
set(PANDA_USE_FUTEX 1)
|
||||
endif()
|
||||
add_definitions(-DPANDA_TARGET_LINUX)
|
||||
add_definitions(-DPANDA_TARGET_UNIX)
|
||||
if (NOT PANDA_ENABLE_ADDRESS_SANITIZER)
|
||||
add_definitions(-DPANDA_USE_FUTEX)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL OHOS)
|
||||
set(PANDA_TARGET_OHOS 1)
|
||||
set(PANDA_TARGET_UNIX 1)
|
||||
add_definitions(-DPANDA_TARGET_OHOS)
|
||||
add_definitions(-DPANDA_TARGET_UNIX)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
set(PANDA_TARGET_WINDOWS 1)
|
||||
add_definitions(-DPANDA_TARGET_WINDOWS)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
|
||||
set(PANDA_TARGET_MACOS 1)
|
||||
set(PANDA_TARGET_UNIX 1)
|
||||
add_definitions(-DPANDA_TARGET_MACOS)
|
||||
add_definitions(-DPANDA_TARGET_UNIX)
|
||||
else()
|
||||
message(FATAL_ERROR "Platform ${CMAKE_SYSTEM_NAME} is not supported")
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
||||
if(NOT PANDA_CROSS_AMD64_X86)
|
||||
set(PANDA_TARGET_AMD64 1)
|
||||
add_definitions(-DPANDA_TARGET_AMD64)
|
||||
else()
|
||||
set(PANDA_TARGET_X86 1)
|
||||
add_definitions(-DPANDA_TARGET_X86)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i[356]86")
|
||||
set(PANDA_TARGET_X86 1)
|
||||
add_definitions(-DPANDA_TARGET_X86)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
set(PANDA_TARGET_ARM64 1)
|
||||
add_definitions(-DPANDA_TARGET_ARM64)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
|
||||
set(PANDA_TARGET_ARM32 1)
|
||||
add_definitions(-DPANDA_TARGET_ARM32)
|
||||
if(PANDA_TARGET_ARM32_ABI_SOFT)
|
||||
add_definitions(-DPANDA_TARGET_ARM32_ABI_SOFT)
|
||||
elseif(PANDA_TARGET_ARM32_ABI_HARD)
|
||||
add_definitions(-DPANDA_TARGET_ARM32_ABI_HARD)
|
||||
else()
|
||||
message(FATAL_ERROR "PANDA_TARGET_ARM32_ABI_* is not set")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Processor ${CMAKE_SYSTEM_PROCESSOR} is not supported")
|
||||
endif()
|
||||
|
||||
if(PANDA_TARGET_AMD64 OR PANDA_TARGET_ARM64)
|
||||
set(PANDA_TARGET_64 1)
|
||||
add_definitions(-DPANDA_TARGET_64)
|
||||
elseif(PANDA_TARGET_X86 OR PANDA_TARGET_ARM32)
|
||||
set(PANDA_TARGET_32 1)
|
||||
add_definitions(-DPANDA_TARGET_32)
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown bitness of the target platform")
|
||||
endif()
|
||||
|
||||
if (PANDA_TRACK_INTERNAL_ALLOCATIONS)
|
||||
message(STATUS "Track internal allocations")
|
||||
add_definitions(-DTRACK_INTERNAL_ALLOCATIONS=${PANDA_TRACK_INTERNAL_ALLOCATIONS})
|
||||
endif()
|
||||
|
||||
# Enable global register variables usage only for clang >= 9.0.0 and gcc >= 8.0.0.
|
||||
# Clang 8.0.0 doesn't support all necessary options -ffixed-<reg>. Gcc 7.5.0 freezes
|
||||
# when compiling release interpreter.
|
||||
#
|
||||
# Also calling conventions of funtions that use global register variables are different:
|
||||
# clang stores and restores registers that are used for global variables in the prolog
|
||||
# and epilog of such functions and gcc doesn't do it. So it's necessary to inline all
|
||||
# function that refers to global register variables to interpreter loop.
|
||||
|
||||
# For this reason we disable global register variables usage for clang debug builds as
|
||||
# ALWAYS_INLINE macro expands to nothing in this mode and we cannot garantee that all
|
||||
# necessary function will be inlined.
|
||||
#
|
||||
if(PANDA_TARGET_ARM64 AND ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
|
||||
AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0.0
|
||||
AND CMAKE_BUILD_TYPE MATCHES Release)
|
||||
OR
|
||||
(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
|
||||
AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0.0)))
|
||||
set(PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES 1)
|
||||
add_definitions(-DPANDA_ENABLE_GLOBAL_REGISTER_VARIABLES)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
# Additional debug information about fp in each frame
|
||||
add_compile_options(-fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
if (PANDA_PGO_INSTRUMENT OR PANDA_PGO_OPTIMIZE)
|
||||
if (NOT PANDA_TARGET_MOBILE OR NOT PANDA_TARGET_ARM64)
|
||||
message(FATAL_ERROR "PGO supported is not supported on this target")
|
||||
endif()
|
||||
|
||||
set(PANDA_ENABLE_LTO true)
|
||||
endif()
|
||||
|
||||
if(PANDA_TARGET_64)
|
||||
set(PANDA_USE_32_BIT_POINTER 1)
|
||||
add_definitions(-DPANDA_USE_32_BIT_POINTER)
|
||||
endif()
|
||||
|
||||
if(PANDA_TARGET_LINUX)
|
||||
execute_process(COMMAND grep PRETTY_NAME= /etc/os-release
|
||||
OUTPUT_VARIABLE PANDA_TARGET_LINUX_DISTRO
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(PANDA_TARGET_LINUX_DISTRO MATCHES "Ubuntu")
|
||||
set(PANDA_TARGET_LINUX_UBUNTU 1)
|
||||
add_definitions(-DPANDA_TARGET_LINUX_UBUNTU)
|
||||
endif()
|
||||
|
||||
if(PANDA_TARGET_LINUX_DISTRO MATCHES "Ubuntu 18\\.04")
|
||||
set(PANDA_TARGET_LINUX_UBUNTU_18_04 1)
|
||||
add_definitions(-DPANDA_TARGET_LINUX_UBUNTU_18_04)
|
||||
elseif(PANDA_TARGET_LINUX_DISTRO MATCHES "Ubuntu 20\\.04")
|
||||
set(PANDA_TARGET_LINUX_UBUNTU_20_04 1)
|
||||
add_definitions(-DPANDA_TARGET_LINUX_UBUNTU_20_04)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(PANDA_WITH_RUNTIME true)
|
||||
set(PANDA_WITH_TOOLCHAIN true)
|
||||
set(PANDA_WITH_TESTS true)
|
||||
set(PANDA_WITH_BENCHMARKS true)
|
||||
set(PANDA_DEFAULT_LIB_TYPE "SHARED")
|
||||
set(DONT_USE_RAPIDCHECK true)
|
||||
|
||||
option(PANDA_ARK_JS_VM "Build with C intepreter in ecmascript folder" OFF)
|
||||
|
||||
if(PANDA_TARGET_WINDOWS)
|
||||
set(PANDA_WITH_BENCHMARKS false)
|
||||
set(PANDA_DEFAULT_LIB_TYPE "STATIC")
|
||||
endif()
|
||||
|
||||
if(PANDA_TARGET_MACOS)
|
||||
set(PANDA_DEFAULT_LIB_TYPE "STATIC")
|
||||
#introduced for "std::filesystem::create_directories"
|
||||
add_compile_options(-mmacosx-version-min=10.15)
|
||||
endif()
|
||||
|
||||
if(PANDA_TARGET_OHOS)
|
||||
set(PANDA_WITH_BENCHMARKS false)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL FastVerify)
|
||||
add_definitions(-DFAST_VERIFY)
|
||||
endif()
|
||||
|
||||
# The definition is set for the build which will be delivered to customers.
|
||||
# Currently this build doesn't contain dependencies to debug libraries
|
||||
# (like libdwarf.so)
|
||||
if (NOT DEFINED PANDA_PRODUCT_BUILD)
|
||||
set(PANDA_PRODUCT_BUILD false)
|
||||
endif()
|
||||
|
||||
if (PANDA_PRODUCT_BUILD)
|
||||
add_definitions(-DPANDA_PRODUCT_BUILD)
|
||||
endif()
|
||||
|
||||
message(STATUS "PANDA_TARGET_UNIX = ${PANDA_TARGET_UNIX}")
|
||||
message(STATUS "PANDA_TARGET_LINUX = ${PANDA_TARGET_LINUX}")
|
||||
message(STATUS "PANDA_TARGET_MOBILE = ${PANDA_TARGET_MOBILE}")
|
||||
message(STATUS "PANDA_USE_FUTEX = ${PANDA_USE_FUTEX}")
|
||||
message(STATUS "PANDA_TARGET_WINDOWS = ${PANDA_TARGET_WINDOWS}")
|
||||
message(STATUS "PANDA_TARGET_OHOS = ${PANDA_TARGET_OHOS}")
|
||||
message(STATUS "PANDA_TARGET_MACOS = ${PANDA_TARGET_MACOS}")
|
||||
message(STATUS "PANDA_CROSS_AMD64_X86 = ${PANDA_CROSS_AMD64_X86}")
|
||||
message(STATUS "PANDA_TARGET_AMD64 = ${PANDA_TARGET_AMD64}")
|
||||
message(STATUS "PANDA_TARGET_X86 = ${PANDA_TARGET_X86}")
|
||||
message(STATUS "PANDA_TARGET_ARM64 = ${PANDA_TARGET_ARM64}")
|
||||
message(STATUS "PANDA_TARGET_ARM32 = ${PANDA_TARGET_ARM32}")
|
||||
if(PANDA_TARGET_ARM32)
|
||||
message(STATUS "PANDA_TARGET_ARM32_ABI_SOFT = ${PANDA_TARGET_ARM32_ABI_SOFT}")
|
||||
message(STATUS "PANDA_TARGET_ARM32_ABI_HARD = ${PANDA_TARGET_ARM32_ABI_HARD}")
|
||||
endif()
|
||||
message(STATUS "PANDA_TARGET_64 = ${PANDA_TARGET_64}")
|
||||
message(STATUS "PANDA_TARGET_32 = ${PANDA_TARGET_32}")
|
||||
message(STATUS "PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES = ${PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES}")
|
||||
message(STATUS "PANDA_ENABLE_LTO = ${PANDA_ENABLE_LTO}")
|
||||
if(PANDA_TARGET_MOBILE)
|
||||
message(STATUS "PANDA_LLVM_REGALLOC = ${PANDA_LLVM_REGALLOC}")
|
||||
endif()
|
||||
message(STATUS "PANDA_WITH_RUNTIME = ${PANDA_WITH_RUNTIME}")
|
||||
message(STATUS "PANDA_WITH_COMPILER = ${PANDA_WITH_COMPILER}")
|
||||
message(STATUS "PANDA_WITH_TOOLCHAIN = ${PANDA_WITH_TOOLCHAIN}")
|
||||
message(STATUS "PANDA_WITH_TESTS = ${PANDA_WITH_TESTS}")
|
||||
message(STATUS "PANDA_WITH_BENCHMARKS = ${PANDA_WITH_BENCHMARKS}")
|
||||
message(STATUS "PANDA_PGO_INSTRUMENT = ${PANDA_PGO_INSTRUMENT}")
|
||||
message(STATUS "PANDA_PGO_OPTIMIZE = ${PANDA_PGO_OPTIMIZE}")
|
||||
message(STATUS "PANDA_PRODUCT_BUILD = ${PANDA_PRODUCT_BUILD}")
|
||||
@@ -0,0 +1,59 @@
|
||||
# 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.
|
||||
|
||||
# To build parts of the platform written in Panda Assembly,
|
||||
# we need to have the assembler binary. If we are not
|
||||
# cross-compiling, we are good to go. Otherwise a subset
|
||||
# of source tree is exposed as a separate project for
|
||||
# "host tools", which is built solely for host.
|
||||
|
||||
function(panda_configure_host_tools)
|
||||
if(NOT CMAKE_CROSSCOMPILING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
set(host_tools_dir "${CMAKE_CURRENT_BINARY_DIR}/host-tools")
|
||||
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_LIST_DIR}/host-tools-CMakeLists.txt"
|
||||
"${host_tools_dir}/CMakeLists.txt"
|
||||
@ONLY ESCAPE_QUOTES)
|
||||
|
||||
if ($ENV{NPROC_PER_JOB})
|
||||
set(PANDA_HOST_TOOLS_JOBS_NUMBER $ENV{NPROC_PER_JOB})
|
||||
else()
|
||||
set(PANDA_HOST_TOOLS_JOBS_NUMBER 16)
|
||||
endif()
|
||||
|
||||
add_custom_target(compiler_host_tools-depend)
|
||||
|
||||
ExternalProject_Add(panda_host_tools
|
||||
DEPENDS compiler_host_tools-depend
|
||||
SOURCE_DIR "${host_tools_dir}"
|
||||
BINARY_DIR "${host_tools_dir}-build"
|
||||
BUILD_IN_SOURCE FALSE
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} <SOURCE_DIR> -G "${CMAKE_GENERATOR}"
|
||||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
-DPANDA_ROOT_SOURCE_DIR=${PANDA_ROOT}
|
||||
-DPANDA_ROOT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||
-DPANDA_THIRD_PARTY_SOURCES_DIR=${PANDA_THIRD_PARTY_SOURCES_DIR}
|
||||
-DPANDA_THIRD_PARTY_CONFIG_DIR=${PANDA_THIRD_PARTY_CONFIG_DIR}
|
||||
-DPANDA_PRODUCT_BUILD=true
|
||||
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --target all -- -j${PANDA_HOST_TOOLS_JOBS_NUMBER}
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "Skipping install step"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
panda_configure_host_tools()
|
||||
@@ -0,0 +1,431 @@
|
||||
# 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.
|
||||
|
||||
# Add a panda assembly to the project using the specified source file
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# add_panda_assembly(TARGET <name> SOURCE <source> INDIR <input directory> OUTDIR <output directory> TARGETNAME <target file name>)
|
||||
#
|
||||
# Adds a panda assembly target called <name> to be build from <source> file
|
||||
# listed in the command invocation.
|
||||
function(add_panda_assembly)
|
||||
set(prefix ARG)
|
||||
set(noValues)
|
||||
set(singleValues TARGET SOURCE INDIR OUTDIR TARGETNAME)
|
||||
set(multiValues)
|
||||
cmake_parse_arguments(${prefix}
|
||||
"${noValues}"
|
||||
"${singleValues}"
|
||||
"${multiValues}"
|
||||
${ARGN})
|
||||
if (NOT DEFINED ARG_TARGET)
|
||||
message(FATAL_ERROR "Mandatory TARGET argument is not defined.")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARG_SOURCE)
|
||||
message(FATAL_ERROR "Mandatory SOURCE argument is not defined.")
|
||||
endif()
|
||||
|
||||
set(source_file_dir "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
if (DEFINED ARG_INDIR)
|
||||
set(source_file_dir "${ARG_INDIR}")
|
||||
endif()
|
||||
|
||||
set(binary_file_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
if (DEFINED ARG_OUTDIR)
|
||||
set(binary_file_dir "${ARG_OUTDIR}")
|
||||
endif()
|
||||
|
||||
set(target_file_name "${ARG_TARGET}")
|
||||
|
||||
if (DEFINED ARG_TARGETNAME)
|
||||
set(target_file_name "${ARG_TARGETNAME}")
|
||||
endif()
|
||||
|
||||
if (TARGET ARG_TARGET)
|
||||
message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.")
|
||||
endif()
|
||||
|
||||
set(source_file "${source_file_dir}/${ARG_SOURCE}")
|
||||
set(binary_file "${binary_file_dir}/${target_file_name}.abc")
|
||||
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
ExternalProject_Get_Property(panda_host_tools binary_dir)
|
||||
set(assembler_target panda_host_tools)
|
||||
set(assembler_bin "${binary_dir}/assembler/ark_asm")
|
||||
else()
|
||||
set(assembler_target ark_asm)
|
||||
set(assembler_bin $<TARGET_FILE:${assembler_target}>)
|
||||
endif()
|
||||
|
||||
add_custom_target(${ARG_TARGET}
|
||||
COMMENT "Building ${ARG_TARGET}"
|
||||
COMMAND "${assembler_bin}" "${source_file}" "${binary_file}"
|
||||
DEPENDS ${assembler_target} "${source_file}")
|
||||
endfunction()
|
||||
|
||||
# Add a single buildable and runnable Panda Assembly file to the build tree.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# panda_add_asm_file(
|
||||
# FILE <source>
|
||||
# TARGET <target>
|
||||
# [ENTRY <entry_point>]
|
||||
# [SUBDIR <subdir>]
|
||||
# [OUTPUT_FILE_VARIABLE <variable>]
|
||||
# [ERROR_FILE_VARIABLE <variable>]
|
||||
# [SKIP_BUILD TRUE|FALSE]
|
||||
# [AOT_MODE TRUE|FALSE]
|
||||
# [DEPENDS <dependency>...]
|
||||
# [RUNTIME_OPTIONS <option>...]
|
||||
# [COMPILER_OPTIONS <option>...]
|
||||
# [GC_OPTIONS <option>]
|
||||
# [ENTRY_ARGUMENTS <argument>...]
|
||||
# [TIMEOUT <timeout>]
|
||||
# [LANGUAGE_CONTEXT <language>]
|
||||
# )
|
||||
#
|
||||
# Adds a target <target> which assembles the assembly file <source>
|
||||
# with Panda assembler and runs it with Panda interpreter.
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# ENTRY
|
||||
# Entry point to execute in format <Class>::<method>. By default _GLOBAL::main is used
|
||||
#
|
||||
# SUBDIR
|
||||
# Subdirectory in the current binary directory that is used to store build artifacts.
|
||||
# Full path to directory with artifacts: ${CMAKE_CURRENT_BINARY_DIR}/<subdir>/<target>
|
||||
#
|
||||
# OUTPUT_FILE_VARIABLE, ERROR_FILE_VARIABLE
|
||||
# The variable named will be set with the paths to files with contents of the stdout and
|
||||
# stderr of the program respectively
|
||||
#
|
||||
# DEPENDS
|
||||
# List of additional dependences (exclude assembler and interpreter)
|
||||
#
|
||||
# RUNTIME_OPTIONS
|
||||
# Runtime options
|
||||
#
|
||||
# COMPILER_OPTIONS
|
||||
# Options for compiler, given both to panda and paoc
|
||||
#
|
||||
# GC_OPTIONS
|
||||
# Type of a gc
|
||||
#
|
||||
# ENTRY_ARGUMENTS
|
||||
# List of arguments that will be passed to program's entry point
|
||||
#
|
||||
# TIMEOUT
|
||||
# If specified, the program will be run and terminated with the signal 10 (corresponds
|
||||
# to SIGUSR1 on most platforms) after the given timeout. The format of the value
|
||||
# must match the `timeout` command. The run will be considered successful if the program
|
||||
# exits before the timeout with the successful exit code or if it is terminated
|
||||
# after the timeout with the signal 10.
|
||||
#
|
||||
# LANGUAGE_CONTEXT
|
||||
# Set the language-dependent semantics for the code. Possible values: panda-assembly.
|
||||
#
|
||||
function(panda_add_asm_file)
|
||||
set(prefix ARG)
|
||||
set(noValues)
|
||||
set(singleValues FILE ENTRY TARGET SUBDIR OUTPUT_FILE_VARIABLE ERROR_FILE_VARIABLE SKIP_BUILD AOT_MODE TIMEOUT LANGUAGE_CONTEXT GC_OPTIONS)
|
||||
set(multiValues DEPENDS RUNTIME_OPTIONS COMPILER_OPTIONS ENTRY_ARGUMENTS PRLIMIT_OPTIONS ADDITIONAL_STDLIBS)
|
||||
cmake_parse_arguments(${prefix}
|
||||
"${noValues}"
|
||||
"${singleValues}"
|
||||
"${multiValues}"
|
||||
${ARGN})
|
||||
|
||||
if (NOT DEFINED ARG_FILE)
|
||||
message(FATAL_ERROR "Mandatory FILE argument is not defined.")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARG_TARGET)
|
||||
message(FATAL_ERROR "Mandatory TARGET argument is not defined.")
|
||||
endif()
|
||||
|
||||
if (TARGET ARG_TARGET)
|
||||
message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.")
|
||||
endif()
|
||||
|
||||
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBDIR}/${ARG_TARGET}")
|
||||
set(build_log "${build_dir}/build.log")
|
||||
set(build_out "${build_dir}/build.out")
|
||||
set(build_err "${build_dir}/build.err")
|
||||
set(binary_file "${build_dir}/test.abc")
|
||||
set(launch_file "${build_dir}/launch.sh")
|
||||
set(output_file "${build_dir}/run.out")
|
||||
set(error_file "${build_dir}/run.err")
|
||||
|
||||
file(MAKE_DIRECTORY "${build_dir}")
|
||||
|
||||
if (DEFINED ARG_OUTPUT_FILE_VARIABLE)
|
||||
set(${ARG_OUTPUT_FILE_VARIABLE} "${output_file}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if (DEFINED ARG_ERROR_FILE_VARIABLE)
|
||||
set(${ARG_ERROR_FILE_VARIABLE} "${error_file}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if (ARG_SKIP_BUILD)
|
||||
set(binary_file "${ARG_FILE}")
|
||||
else()
|
||||
set(assembler ark_asm)
|
||||
add_custom_command(OUTPUT "${binary_file}"
|
||||
COMMENT "Building ${ARG_TARGET}"
|
||||
COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:${assembler}> --verbose --log-file "${build_log}" "${ARG_FILE}" "${binary_file}" 1>"${build_out}" 2>"${build_err}"
|
||||
DEPENDS ${assembler} "${ARG_FILE}")
|
||||
endif()
|
||||
|
||||
if (DEFINED ARG_TIMEOUT AND NOT "${ARG_TIMEOUT}" STREQUAL "")
|
||||
set(timeout_signal 10)
|
||||
set(timeout_prefix "timeout --preserve-status --signal=${timeout_signal} --kill-after=10s ${ARG_TIMEOUT}")
|
||||
set(timeout_suffix "|| [ `expr \$? % 128` -eq ${timeout_signal} ]")
|
||||
else()
|
||||
set(timeout_prefix "")
|
||||
set(timeout_suffix "")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARG_ENTRY)
|
||||
set(ARG_ENTRY "_GLOBAL::main")
|
||||
endif()
|
||||
|
||||
set(panda_stdlib arkstdlib)
|
||||
set(panda_cli ark)
|
||||
set(panda_verifier verifier)
|
||||
|
||||
set(stdlibs "${${panda_stdlib}_BINARY_DIR}/${panda_stdlib}.abc")
|
||||
if (DEFINED ARG_ADDITIONAL_STDLIBS)
|
||||
list(APPEND stdlibs ${ARG_ADDITIONAL_STDLIBS})
|
||||
endif()
|
||||
|
||||
set(spaces "core")
|
||||
set(runtime_type "core")
|
||||
if (DEFINED ARG_LANGUAGE_CONTEXT AND NOT "${ARG_LANGUAGE_CONTEXT}" STREQUAL "panda-assembly")
|
||||
list(APPEND spaces "${ARG_LANGUAGE_CONTEXT}")
|
||||
set(runtime_type "${ARG_LANGUAGE_CONTEXT}")
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" ":" boot_stdlibs "${stdlibs}")
|
||||
string(REPLACE ";" ":" boot_spaces "${spaces}")
|
||||
|
||||
# Note well! The lines below imply that we cannot handle ";" properly
|
||||
# in both Panda's own options and the running program's options.
|
||||
string(REPLACE ";" " " runtime_options "${ARG_COMPILER_OPTIONS} ${ARG_RUNTIME_OPTIONS}")
|
||||
string(REPLACE ";" " " entry_arguments "${ARG_ENTRY_ARGUMENTS}")
|
||||
|
||||
set(prlimit_cmd "")
|
||||
if (DEFINED ARG_PRLIMIT_OPTIONS)
|
||||
set(prlimit_cmd "prlimit ${ARG_PRLIMIT_OPTIONS}")
|
||||
string(REPLACE ";" " " prlimit_cmd "${prlimit_cmd}")
|
||||
endif()
|
||||
|
||||
if (${runtime_options} MATCHES ".*events-output=csv.*")
|
||||
set(runtime_options "${runtime_options} --events-file=${build_dir}/events.csv")
|
||||
endif()
|
||||
|
||||
set(launcher
|
||||
"${timeout_prefix}"
|
||||
"${prlimit_cmd}"
|
||||
"${PANDA_RUN_PREFIX}"
|
||||
$<TARGET_FILE:${panda_cli}>
|
||||
"--boot-panda-files \"${boot_stdlibs}\""
|
||||
"--boot-intrinsic-spaces=${boot_spaces}"
|
||||
"--boot-class-spaces=${boot_spaces}"
|
||||
"--runtime-type=${runtime_type}"
|
||||
"${runtime_options}"
|
||||
"\"${binary_file}\""
|
||||
"\"${ARG_ENTRY}\""
|
||||
"${entry_arguments}"
|
||||
"1>\"${output_file}\""
|
||||
"2>\"${error_file}\""
|
||||
"${timeout_suffix}"
|
||||
)
|
||||
string(REPLACE ";" " " launcher "${launcher}")
|
||||
file(GENERATE OUTPUT ${launch_file} CONTENT "${launcher}")
|
||||
|
||||
add_custom_target(${ARG_TARGET}
|
||||
COMMENT "Running ${ARG_TARGET}"
|
||||
COMMAND . ${launch_file} || (cat ${error_file} && false)
|
||||
DEPENDS ${panda_cli} ${panda_stdlib} "${binary_file}" ${aot_file})
|
||||
|
||||
if (DEFINED ARG_DEPENDS)
|
||||
add_dependencies(${ARG_TARGET} ${ARG_DEPENDS})
|
||||
endif()
|
||||
|
||||
|
||||
endfunction()
|
||||
|
||||
# Add a single buildable and verifiable Panda Assembly file to the build tree.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# verifier_add_asm_file(
|
||||
# FILE <source>
|
||||
# TARGET <target>
|
||||
# [ENTRY <entry_point>]
|
||||
# [RUNTIME_OPTIONS <runtime options>]
|
||||
# [VERIFIER_OPTIONS <verifier options>]
|
||||
# [SUBDIR <subdir>]
|
||||
# [OUTPUT_FILE_VARIABLE <variable>]
|
||||
# [ERROR_FILE_VARIABLE <variable>]
|
||||
# [DEPENDS <dependency>...]
|
||||
# [TIMEOUT <timeout>]
|
||||
# [LANGUAGE_CONTEXT <language>]
|
||||
# )
|
||||
#
|
||||
# Adds a target <target> which assembles the assembly file <source>
|
||||
# with Panda assembler and verifies it with verifier.
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# ENTRY
|
||||
# Entry point to execute in format <Class>::<method>. By default _GLOBAL::main is used
|
||||
#
|
||||
# SUBDIR
|
||||
# Subdirectory in the current binary directory that is used to store build artifacts.
|
||||
# Full path to directory with artifacts: ${CMAKE_CURRENT_BINARY_DIR}/<subdir>/<target>
|
||||
#
|
||||
# OUTPUT_FILE_VARIABLE, ERROR_FILE_VARIABLE
|
||||
# The variable named will be set with the paths to files with contents of the stdout and
|
||||
# stderr of the program respectively
|
||||
#
|
||||
# DEPENDS
|
||||
# List of additional dependences (exclude assembler and interpreter)
|
||||
#
|
||||
# RUNTIME_OPTIONS
|
||||
# Runtime initialization options
|
||||
#
|
||||
# VERIFIER_OPTIONS
|
||||
# Verifier CLI options
|
||||
#
|
||||
# TIMEOUT
|
||||
# If specified, the program will be run and terminated with the signal 10 (corresponds
|
||||
# to SIGUSR1 on most platforms) after the given timeout. The format of the value
|
||||
# must match the `timeout` command. The run will be considered successful if the program
|
||||
# exits before the timeout with the successful exit code or if it is terminated
|
||||
# after the timeout with the signal 10.
|
||||
#
|
||||
# LANGUAGE_CONTEXT
|
||||
# Set the language-dependent semantics for the code. Possible values: panda-assembly.
|
||||
#
|
||||
function(verifier_add_asm_file)
|
||||
set(prefix ARG)
|
||||
set(noValues)
|
||||
set(singleValues FILE ENTRY TARGET SUBDIR OUTPUT_FILE_VARIABLE ERROR_FILE_VARIABLE TIMEOUT LANGUAGE_CONTEXT)
|
||||
set(multiValues DEPENDS RUNTIME_OPTIONS VERIFIER_OPTIONS)
|
||||
cmake_parse_arguments(${prefix}
|
||||
"${noValues}"
|
||||
"${singleValues}"
|
||||
"${multiValues}"
|
||||
${ARGN})
|
||||
|
||||
if (NOT DEFINED ARG_FILE)
|
||||
message(FATAL_ERROR "Mandatory FILE argument is not defined.")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARG_TARGET)
|
||||
message(FATAL_ERROR "Mandatory TARGET argument is not defined.")
|
||||
endif()
|
||||
|
||||
if (TARGET ARG_TARGET)
|
||||
message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.")
|
||||
endif()
|
||||
|
||||
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/${ARG_SUBDIR}/${ARG_TARGET}")
|
||||
set(build_out "${build_dir}/build.out")
|
||||
set(build_err "${build_dir}/build.err")
|
||||
set(binary_file "${build_dir}/test.abc")
|
||||
set(launch_file "${build_dir}/verifier_launch.sh")
|
||||
set(output_file "${build_dir}/verify.out")
|
||||
set(error_file "${build_dir}/verify.err")
|
||||
|
||||
file(MAKE_DIRECTORY "${build_dir}")
|
||||
|
||||
if (DEFINED ARG_OUTPUT_FILE_VARIABLE)
|
||||
set(${ARG_OUTPUT_FILE_VARIABLE} "${output_file}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if (DEFINED ARG_ERROR_FILE_VARIABLE)
|
||||
set(${ARG_ERROR_FILE_VARIABLE} "${error_file}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
set(assembler ark_asm)
|
||||
add_custom_command(OUTPUT "${binary_file}"
|
||||
COMMENT "Building ${ARG_TARGET}"
|
||||
COMMAND ${PANDA_RUN_PREFIX} $<TARGET_FILE:${assembler}> "${ARG_FILE}" "${binary_file}" 1>"${build_out}" 2>"${build_err}"
|
||||
DEPENDS ${assembler} "${ARG_FILE}")
|
||||
|
||||
if (DEFINED ARG_TIMEOUT AND NOT "${ARG_TIMEOUT}" STREQUAL "")
|
||||
set(timeout_signal 10)
|
||||
set(timeout_prefix "timeout --preserve-status --signal=${timeout_signal} --kill-after=10s ${ARG_TIMEOUT}")
|
||||
set(timeout_suffix "|| [ `expr \$? % 128` -eq ${timeout_signal} ]")
|
||||
else()
|
||||
set(timeout_prefix "")
|
||||
set(timeout_suffix "")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARG_ENTRY)
|
||||
set(ARG_ENTRY "_GLOBAL::main")
|
||||
endif()
|
||||
|
||||
set(panda_stdlib arkstdlib)
|
||||
set(verifier_cli ark)
|
||||
|
||||
set(stdlibs "${${panda_stdlib}_BINARY_DIR}/${panda_stdlib}.abc")
|
||||
set(spaces "core")
|
||||
set(runtime_type "core")
|
||||
if (NOT DEFINED ARG_LANGUAGE_CONTEXT)
|
||||
set(ARG_LANGUAGE_CONTEXT "panda-assembly")
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" ":" boot_stdlibs "${stdlibs}")
|
||||
string(REPLACE ";" ":" boot_spaces "${spaces}")
|
||||
|
||||
if(NOT "${ARG_VERIFIER_OPTIONS}" STREQUAL "")
|
||||
set(ARG_VERIFIER_OPTIONS ",${ARG_VERIFIER_OPTIONS}")
|
||||
endif()
|
||||
|
||||
set(launcher_verifier
|
||||
"${PANDA_RUN_PREFIX}"
|
||||
$<TARGET_FILE:${verifier_cli}>
|
||||
"--verification-enabled"
|
||||
"--verification-options only-verify${ARG_VERIFIER_OPTIONS}"
|
||||
"${ARG_RUNTIME_OPTIONS}"
|
||||
"--boot-panda-files \"${boot_stdlibs}\""
|
||||
"--boot-intrinsic-spaces=${boot_spaces}"
|
||||
"--boot-class-spaces=${boot_spaces}"
|
||||
"--runtime-type=${runtime_type}"
|
||||
"\"${binary_file}\""
|
||||
"\"${ARG_ENTRY}\""
|
||||
"1>\"${output_file}\""
|
||||
"2>\"${error_file}\""
|
||||
)
|
||||
string(REPLACE ";" " " launcher_verifier "${launcher_verifier}")
|
||||
file(GENERATE OUTPUT ${launch_file} CONTENT "${launcher_verifier}")
|
||||
|
||||
add_custom_target(${ARG_TARGET}
|
||||
COMMENT "Verifying ${ARG_TARGET}"
|
||||
COMMAND . ${launch_file}
|
||||
DEPENDS ${verifier_cli} "${binary_file}")
|
||||
|
||||
if (DEFINED ARG_DEPENDS)
|
||||
add_dependencies(${ARG_TARGET} ${ARG_DEPENDS})
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
@@ -0,0 +1,19 @@
|
||||
# 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.
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
message(STATUS "CCACHE_FOUND = 1")
|
||||
endif(CCACHE_FOUND)
|
||||
@@ -0,0 +1,61 @@
|
||||
# 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.
|
||||
|
||||
# 32-bits pointers optimization in Panda for objects => addresses usage low 4GB
|
||||
# We need use linker scripts for section replacement above 4GB
|
||||
# Note: AdressSanitizer reserves (mmap) addresses for its own needs,
|
||||
# so we have difference start addresses for asan and default buildings
|
||||
function(panda_add_executable target)
|
||||
# When using rapidcheck we should use linker scripts with
|
||||
# definitions for exception handling sections
|
||||
cmake_parse_arguments(ARG "RAPIDCHECK_ON" "" "" ${ARGN})
|
||||
|
||||
add_executable(${target} ${ARG_UNPARSED_ARGUMENTS})
|
||||
|
||||
if(PANDA_USE_32_BIT_POINTER AND NOT (PANDA_TARGET_MOBILE OR PANDA_TARGET_WINDOWS OR PANDA_TARGET_MACOS OR PANDA_TARGET_OHOS))
|
||||
if(ARG_RAPIDCHECK_ON)
|
||||
set(LINKER_SCRIPT_ARG "-Wl,-T,${PANDA_ROOT}/ldscripts/panda_test_asan.ld")
|
||||
else()
|
||||
set(LINKER_SCRIPT_ARG "-Wl,-T,${PANDA_ROOT}/ldscripts/panda.ld")
|
||||
endif()
|
||||
if(PANDA_ENABLE_ADDRESS_SANITIZER)
|
||||
# For cross-aarch64 with ASAN with linker script we need use additional path-link
|
||||
# Here we use default addresses space (without ASAN flag). It is nuance of cross-building.
|
||||
if(PANDA_TARGET_ARM64)
|
||||
set(LINKER_SCRIPT_ARG "-Wl,-rpath-link,${PANDA_SYSROOT}/lib ${LINKER_SCRIPT_ARG}")
|
||||
else()
|
||||
set(LINKER_SCRIPT_ARG "-Wl,--defsym,LSFLAG_ASAN=1 ${LINKER_SCRIPT_ARG}")
|
||||
endif()
|
||||
endif()
|
||||
# We need use specific options for AMD64 building with Clang compiler
|
||||
# because it is neccessary for placement of sections above 4GB
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND PANDA_TARGET_AMD64)
|
||||
set(LINKER_SCRIPT_ARG "${LINKER_SCRIPT_ARG} -pie")
|
||||
# -mcmodel=large with clang and asan on x64 leads to bugs in rapidcheck with high-mem mappings
|
||||
# so for rapidcheck test binaries panda_test_asan.ld is used which does not require
|
||||
# -mcmodel=large option
|
||||
if(NOT ARG_RAPIDCHECK_ON)
|
||||
target_compile_options(${target} PUBLIC "-mcmodel=large")
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${target} ${LINKER_SCRIPT_ARG})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# This function need for non-SHARED libraries
|
||||
# It is neccessary for 32-bits pointers via amd64 building with Clang compiler
|
||||
function(panda_set_lib_32bit_property target)
|
||||
if(PANDA_USE_32_BIT_POINTER AND PANDA_TARGET_AMD64 AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set_property(TARGET ${target} PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +1,73 @@
|
||||
## Basic build
|
||||
|
||||
Panda libraries can be built using CMake:
|
||||
```
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake ${panda_dir}
|
||||
$ make
|
||||
```
|
||||
|
||||
Here, ${panda_dir} refers to path to panda dirrectory.
|
||||
After this step, create libraries and some debug-targets if you have installed additional libraries, like google-test, clang-format, clang-tidy, etc.
|
||||
|
||||
## Build directory structure
|
||||
|
||||
In the current build, create subdirectories for each project. For example, for the vixl library, create the `third_party/vixl` directory. Add the following command in root CMakeLists.txt:
|
||||
```
|
||||
add_subdirectory(third_party/vixl)
|
||||
```
|
||||
You may use built libraries in your component, e.g. target_link_libraries(tests compiler base vixl). However, for getting variables, use INTERFACE includes, e.g. target_include_directories(INTERFACE .) instead.
|
||||
|
||||
## Run tests
|
||||
|
||||
The tests-binary will also be generated during the build. To run tests, run the following command:
|
||||
```
|
||||
$ make test
|
||||
Running tests...
|
||||
Test project /home/igorban/src/panda_build
|
||||
Start 1: compiler_unit_tests
|
||||
1/1 Test #1: compiler_unit_tests ................... Passed 2.74 sec
|
||||
..
|
||||
```
|
||||
|
||||
## Calculate coverage
|
||||
|
||||
To calculate the test code coverage - just execute it:
|
||||
```
|
||||
$ make coverage
|
||||
```
|
||||
Location of the code coverage report: BUILD_DIR/compiler/coverage_report
|
||||
|
||||
## Check style
|
||||
|
||||
To check the style, perform the previous steps and build style-checker targets. Note that you must install clang-format and clang-tidy with libraries. For details, see scripts/bootstrap*.sh.
|
||||
```
|
||||
$ make clang_format
|
||||
Built target clang_format_opt_tests_graph_creation_test.cpp
|
||||
Built target clang_format_opt_opt.h
|
||||
...
|
||||
|
||||
$ make clang_tidy
|
||||
Scanning dependencies of target copy_json
|
||||
Move compile commands to root directory
|
||||
...
|
||||
Built target copy_json
|
||||
Scanning dependencies of target clang_tidy_opt_codegen_codegen.cpp
|
||||
...
|
||||
```
|
||||
|
||||
You may force fix clang-format issues using the `make clang_force_format` command.
|
||||
Run `make help | grep clang` to see all possible clang-[format|style] targets.
|
||||
For issues in opt.cpp, you may check the style through clang-format `make clang_format_opt_opt.cpp`, or through clang-tidy `make clang_tidy_opt_opt.cpp`. For the force clang-format code style, use `make clang_force_format_opt_opt.cpp`.
|
||||
For code-style check through one check system, use `make clang_tidy` or `make clang_format`.
|
||||
|
||||
Generated files:
|
||||
* `compile_commands.json` - json nija-commands file to correct execution clang-tidy.
|
||||
* Standard cmake-files: `CMakeCache.txt`, `Makefile`, `cmake_install.cmake` and folder `CMakeFiles`.
|
||||
|
||||
|
||||
Discussion about format : rus-os-team/virtual-machines-and-tools/vm-investigation-and-design#24
|
||||
* Clang-tidy style file - `.clang-tidy`
|
||||
* Clang-format style file - `.clang-format`
|
||||
* Script to show diff through clang-format execution - `build/run-clang-format.py`
|
||||
@@ -0,0 +1,90 @@
|
||||
# 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.
|
||||
|
||||
option(PANDA_ENABLE_SANITIZE_TRAP "Enable sanitizer trap generation" false)
|
||||
if (CMAKE_BUILD_TYPE MATCHES Release)
|
||||
set(PANDA_ENABLE_SANITIZE_TRAP true)
|
||||
endif ()
|
||||
|
||||
option(PANDA_ENABLE_ADDRESS_SANITIZER "Address sanitizer enable" false)
|
||||
option(PANDA_ENABLE_UNDEFINED_BEHAVIOR_SANITIZER "Undefined behavior sanitizer enable" false)
|
||||
option(PANDA_ENABLE_THREAD_SANITIZER "Thread sanitizer enable" false)
|
||||
|
||||
set(PANDA_SANITIZERS_LIST)
|
||||
|
||||
if (PANDA_ENABLE_ADDRESS_SANITIZER)
|
||||
message(STATUS "Enabled ASAN")
|
||||
list(APPEND PANDA_SANITIZERS_LIST "address")
|
||||
endif()
|
||||
|
||||
if (PANDA_ENABLE_UNDEFINED_BEHAVIOR_SANITIZER)
|
||||
message(STATUS "Enabled UBSAN")
|
||||
list(APPEND PANDA_SANITIZERS_LIST "undefined")
|
||||
# GCC doesn't have built-in macro for UBSAN, bypass by making our own definition.
|
||||
add_definitions(-D__SANITIZE_UNDEFINED__)
|
||||
endif()
|
||||
|
||||
if (PANDA_ENABLE_THREAD_SANITIZER)
|
||||
message(STATUS "Enabled TSAN")
|
||||
list(APPEND PANDA_SANITIZERS_LIST "thread")
|
||||
endif()
|
||||
|
||||
# Workaround for issue 529
|
||||
# As of the beginning of May 2020 we have checked: gcc 7.5.0, gcc 8.4.0, gcc 9.3.0 and 10.0-rc versions, all have
|
||||
# some false-positive or another issues when compiling with ASAN or UBSAN in release mode. So, cover this with early-bailout.
|
||||
if ((PANDA_ENABLE_ADDRESS_SANITIZER OR PANDA_ENABLE_UNDEFINED_BEHAVIOR_SANITIZER) AND
|
||||
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND (CMAKE_BUILD_TYPE MATCHES Release))
|
||||
message(FATAL_ERROR "GCC gives false positives in release builds with ASAN or UBSAN, please use clang or another compiler.")
|
||||
unset(build_type)
|
||||
endif()
|
||||
|
||||
# Add options to build with sanitizers to specified target
|
||||
#
|
||||
# Example usage:
|
||||
# panda_add_sanitizers(TARGET <name> SANITIZERS <sanitizer1>,<sanitizer2>)
|
||||
#
|
||||
# Adds options to build target <name> with <sanitizer1> and <sanitizer2>
|
||||
#
|
||||
# Available sanitizers: address, thread, undefined
|
||||
|
||||
function(panda_add_sanitizers)
|
||||
set(prefix ARG)
|
||||
set(noValues)
|
||||
set(singleValues TARGET)
|
||||
set(multiValues SOURCES SANITIZERS)
|
||||
|
||||
cmake_parse_arguments(${prefix}
|
||||
"${noValues}"
|
||||
"${singleValues}"
|
||||
"${multiValues}"
|
||||
${ARGN})
|
||||
|
||||
if(ARG_SANITIZERS)
|
||||
set(AVAILABLE_SANITIZERS "address" "undefined" "thread")
|
||||
foreach(sanitizer ${ARG_SANITIZERS})
|
||||
if(NOT ${sanitizer} IN_LIST AVAILABLE_SANITIZERS)
|
||||
message(FATAL_ERROR "Unknown sanitizer: ${sanitizer}")
|
||||
endif()
|
||||
endforeach()
|
||||
string(REPLACE ";" "," ARG_SANITIZERS "${ARG_SANITIZERS}")
|
||||
target_compile_options(${ARG_TARGET} PUBLIC "-fsanitize=${ARG_SANITIZERS}" -g)
|
||||
if (PANDA_ENABLE_SANITIZE_TRAP)
|
||||
target_compile_options(${ARG_TARGET} PUBLIC "-fsanitize-undefined-trap-on-error")
|
||||
endif()
|
||||
set_target_properties(${ARG_TARGET} PROPERTIES LINK_FLAGS "-fsanitize=${ARG_SANITIZERS}")
|
||||
|
||||
if (PANDA_TARGET_MOBILE)
|
||||
target_link_libraries(${ARG_TARGET} log)
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -0,0 +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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.5.2 FATAL_ERROR)
|
||||
|
||||
# Generate files based on templates and YAML data provided.
|
||||
# Adds targets for every template. Also adds a target for the whole function invocation
|
||||
# with name ${data_name}_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# * DATA -- data source, YAML file
|
||||
# * TEMPLATES -- a list of templates to generate files
|
||||
# * REQUIRES -- a list of Ruby scripts that provide data-querying API for templates
|
||||
#
|
||||
# Optional arguments:
|
||||
# * SOURCE -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates
|
||||
# * DESTINATION -- a directory for output files, default is ${PANDA_BINARY_ROOT}
|
||||
# * EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies
|
||||
|
||||
function(panda_gen)
|
||||
set(singlevalues DATA SOURCE DESTINATION TARGET_NAME)
|
||||
set(multivalues TEMPLATES REQUIRES EXTRA_DEPENDENCIES)
|
||||
cmake_parse_arguments(
|
||||
GEN_ARG
|
||||
""
|
||||
"${singlevalues}"
|
||||
"${multivalues}"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if (NOT DEFINED GEN_ARG_TEMPLATES)
|
||||
message(FATAL_ERROR "`TEMPLATES` were not passed to `panda_gen` function")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED GEN_ARG_DATA)
|
||||
message(FATAL_ERROR "`DATA` was not passed to `panda_gen` function")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED GEN_ARG_SOURCE)
|
||||
set(GEN_ARG_SOURCE "${PROJECT_SOURCE_DIR}/templates")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED GEN_ARG_DESTINATION)
|
||||
set(GEN_ARG_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED GEN_ARG_TARGET_NAME)
|
||||
get_filename_component(DATA_NAME ${GEN_ARG_DATA} NAME_WE)
|
||||
set(GEN_ARG_TARGET_NAME "${DATA_NAME}_gen_${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
add_custom_target(${GEN_ARG_TARGET_NAME}) # Umbrella target for all generated files
|
||||
|
||||
foreach(t ${GEN_ARG_TEMPLATES})
|
||||
set(TEMPLATE "${GEN_ARG_SOURCE}/${t}")
|
||||
string(REGEX REPLACE "\.erb$" "" NAME ${t})
|
||||
string(REPLACE "\." "_" TARGET ${NAME})
|
||||
string(REPLACE "/" "_" TARGET ${TARGET})
|
||||
set(TARGET ${PROJECT_NAME}_${TARGET})
|
||||
set(OUTPUT_FILE "${GEN_ARG_DESTINATION}/${NAME}")
|
||||
|
||||
panda_gen_file(DATAFILE ${GEN_ARG_DATA}
|
||||
TEMPLATE ${TEMPLATE}
|
||||
OUTPUTFILE ${OUTPUT_FILE}
|
||||
REQUIRES ${GEN_ARG_REQUIRES}
|
||||
EXTRA_DEPENDENCIES ${GEN_ARG_EXTRA_DEPENDENCIES}
|
||||
)
|
||||
add_custom_target(${TARGET} ALL DEPENDS ${OUTPUT_FILE})
|
||||
add_dependencies(${GEN_ARG_TARGET_NAME} ${TARGET})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# Calls `panda_gen` for ISA YAML.
|
||||
# Adds targets for every template. Also adds a target for the whole function invocation
|
||||
# with name isa_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# * TEMPLATES -- a list of templates to generate files
|
||||
#
|
||||
# Optional arguments:
|
||||
# * SOURCE -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates
|
||||
# * DESTINATION -- a directory for output files, default is ${PANDA_BINARY_ROOT}
|
||||
# * REQUIRES -- if defined, will require additional Ruby files for template generation
|
||||
# * EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies
|
||||
|
||||
function(panda_isa_gen)
|
||||
set(singlevalues SOURCE DESTINATION)
|
||||
set(multivalues TEMPLATES REQUIRES EXTRA_DEPENDENCIES)
|
||||
cmake_parse_arguments(
|
||||
ISA_GEN_ARG
|
||||
""
|
||||
"${singlevalues}"
|
||||
"${multivalues}"
|
||||
${ARGN}
|
||||
)
|
||||
set(ISA_DATA "${PANDA_ROOT}/isa/isa.yaml")
|
||||
set(ISAPI "${PANDA_ROOT}/isa/isapi.rb")
|
||||
list(INSERT ISA_GEN_ARG_REQUIRES 0 ${ISAPI})
|
||||
panda_gen(DATA ${ISA_DATA}
|
||||
TEMPLATES ${ISA_GEN_ARG_TEMPLATES}
|
||||
SOURCE ${ISA_GEN_ARG_SOURCE}
|
||||
DESTINATION ${ISA_GEN_ARG_DESTINATION}
|
||||
REQUIRES ${ISA_GEN_ARG_REQUIRES}
|
||||
EXTRA_DEPENDENCIES ${ISA_GEN_ARG_EXTRA_DEPENDENCIES}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Generate file for a template and YAML data provided.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# DATAFILE -- YAML data full name
|
||||
# TEMPLATE -- template full name
|
||||
# OUTPUTFILE -- output file full name
|
||||
# REQUIRES -- a list of scripts that provide data-querying API for templates
|
||||
# EXTRA_DEPENDENCIES -- a list of files that should be considered as dependencies
|
||||
|
||||
function(panda_gen_file)
|
||||
set(singlevalues DATAFILE TEMPLATE OUTPUTFILE)
|
||||
set(multivalues REQUIRES EXTRA_DEPENDENCIES)
|
||||
cmake_parse_arguments(
|
||||
ARG
|
||||
""
|
||||
"${singlevalues}"
|
||||
"${multivalues}"
|
||||
${ARGN}
|
||||
)
|
||||
set(GENERATOR "${PANDA_ROOT}/isa/gen.rb")
|
||||
string(REPLACE ";" "," REQUIRE_STR "${ARG_REQUIRES}")
|
||||
set(DEPENDS_LIST ${GENERATOR} ${ARG_TEMPLATE} ${ARG_DATAFILE})
|
||||
|
||||
foreach(r ${ARG_REQUIRES})
|
||||
list(APPEND DEPENDS_LIST ${r})
|
||||
endforeach()
|
||||
|
||||
foreach(r ${ARG_EXTRA_DEPENDENCIES})
|
||||
list(APPEND DEPENDS_LIST ${r})
|
||||
endforeach()
|
||||
|
||||
add_custom_command(OUTPUT ${ARG_OUTPUTFILE}
|
||||
COMMENT "Generate file for ${ARG_TEMPLATE}"
|
||||
COMMAND ${GENERATOR} --template ${ARG_TEMPLATE} --data ${ARG_DATAFILE} --output ${ARG_OUTPUTFILE} --require ${REQUIRE_STR}
|
||||
DEPENDS ${DEPENDS_LIST}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Create an options header using a YAML file for the target
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# TARGET -- target
|
||||
# YAML_FILE -- YAML file
|
||||
# GENERATED_HEADER -- generated header
|
||||
#
|
||||
# Use "#include 'generated/GENERATED_HEADER"' to include the generated header
|
||||
|
||||
function(panda_gen_options)
|
||||
# Parsing function arguments
|
||||
set(singlevalues TARGET YAML_FILE GENERATED_HEADER)
|
||||
cmake_parse_arguments(GEN_OPTIONS "" "${singlevalues}" "" ${ARGN})
|
||||
|
||||
# Generate an options header
|
||||
get_filename_component(YAML_FILE ${GEN_OPTIONS_YAML_FILE} ABSOLUTE)
|
||||
set(GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/panda_gen_options/generated)
|
||||
file(MAKE_DIRECTORY ${GENERATED_DIR})
|
||||
set(OPTIONS_H ${GENERATED_DIR}/${GEN_OPTIONS_GENERATED_HEADER})
|
||||
panda_gen_file(
|
||||
DATAFILE ${YAML_FILE}
|
||||
TEMPLATE ${PANDA_ROOT}/templates/options/options.h.erb
|
||||
OUTPUTFILE ${OPTIONS_H}
|
||||
REQUIRES ${PANDA_ROOT}/templates/common.rb
|
||||
)
|
||||
|
||||
# Add dependencies for a target
|
||||
target_include_directories(${GEN_OPTIONS_TARGET} PUBLIC ${GENERATED_DIR}/..)
|
||||
add_custom_target(${GEN_OPTIONS_TARGET}_options DEPENDS ${OPTIONS_H})
|
||||
add_dependencies(${GEN_OPTIONS_TARGET} ${GEN_OPTIONS_TARGET}_options)
|
||||
endfunction()
|
||||
|
||||
function(panda_gen_messages)
|
||||
set(singlevalues TARGET YAML_FILE GENERATED_HEADER)
|
||||
cmake_parse_arguments(ARG "" "${singlevalues}" "" ${ARGN})
|
||||
|
||||
if(NOT DEFINED ARG_YAML_FILE)
|
||||
set(ARG_YAML_FILE ${CMAKE_CURRENT_SOURCE_DIR}/messages.yaml)
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED ARG_GENERATED_HEADER)
|
||||
set(ARG_GENERATED_HEADER messages.h)
|
||||
endif()
|
||||
|
||||
get_filename_component(YAML_FILE ${ARG_YAML_FILE} ABSOLUTE)
|
||||
|
||||
if(IS_ABSOLUTE ${ARG_GENERATED_HEADER})
|
||||
get_filename_component(GENERATED_DIR ${ARG_GENERATED_HEADER} DIRECTORY)
|
||||
set(MESSAGES_H ${ARG_GENERATED_HEADER})
|
||||
else()
|
||||
set(INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/panda_gen_messages)
|
||||
set(GENERATED_DIR ${INCLUDE_DIR}/generated)
|
||||
set(MESSAGES_H ${GENERATED_DIR}/${ARG_GENERATED_HEADER})
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${GENERATED_DIR})
|
||||
panda_gen_file(
|
||||
DATAFILE ${YAML_FILE}
|
||||
TEMPLATE ${PANDA_ROOT}/templates/messages/messages.h.erb
|
||||
OUTPUTFILE ${MESSAGES_H}
|
||||
REQUIRES ${PANDA_ROOT}/templates/messages.rb
|
||||
)
|
||||
|
||||
# Add dependencies for a target
|
||||
if (NOT DEFINED ARG_TARGET)
|
||||
set(ARG_TARGET messages_gen_${PROJECT_NAME})
|
||||
add_custom_target(${ARG_TARGET})
|
||||
endif()
|
||||
|
||||
if (DEFINED INCLUDE_DIR)
|
||||
target_include_directories(${ARG_TARGET} PUBLIC ${INCLUDE_DIR})
|
||||
endif()
|
||||
add_custom_target(${ARG_TARGET}_messages DEPENDS ${MESSAGES_H})
|
||||
add_dependencies(${ARG_TARGET} ${ARG_TARGET}_messages)
|
||||
endfunction()
|
||||
@@ -0,0 +1,85 @@
|
||||
# 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.
|
||||
# Convenience functions for testing Panda.
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/CommonTesting.cmake)
|
||||
|
||||
set(PANDA_CI_TESTING_MODE "Default")
|
||||
if(DEFINED ENV{SCHEDULE_NAME})
|
||||
if($ENV{SCHEDULE_NAME} STREQUAL "Nightly")
|
||||
set(PANDA_CI_TESTING_MODE "Nightly")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "PANDA_CI_TESTING_MODE = ${PANDA_CI_TESTING_MODE}")
|
||||
|
||||
if(PANDA_WITH_TESTS)
|
||||
# Target for building all Googletest-based tests:
|
||||
add_custom_target(gtests_build COMMENT "Building gtests")
|
||||
|
||||
# Use a custom target instead of `test` to ensure that running
|
||||
# Googletest-based tests depends on building them:
|
||||
add_custom_target(gtests
|
||||
COMMENT "Running gtests after building them"
|
||||
DEPENDS gtests_build)
|
||||
|
||||
if(NOT PANDA_SKIP_GTESTS)
|
||||
add_dependencies(tests gtests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add Googletest-based tests to the source tree.
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# panda_add_gtest(NAME test_name
|
||||
# OUTPUT_DIRECTORY /path/to/output/dir
|
||||
# SOURCES
|
||||
# tests/unit1_test.c
|
||||
# tests/unit2_test.c
|
||||
# INCLUDE_DIRS
|
||||
# path/to/include1
|
||||
# path/to/include2
|
||||
# LIBRARIES
|
||||
# component1 component2
|
||||
# SANITIZERS sanitizer1,sanitizer2,..
|
||||
# )
|
||||
#
|
||||
# Available sanitizers: address, thread, undefined
|
||||
#
|
||||
# This will create a target test_name which consists of the sources defined
|
||||
# in SOURCES and linked with libraries defined in LIBRARIES. If the list of
|
||||
# paths is specified in INCLUDE_DIRS, these paths will be added as include
|
||||
# directories for the test_name target.
|
||||
#
|
||||
# If OUTPUT_DIRECTORY is not defined, the binary will be put to bin-gtests
|
||||
# directory at the build tree root.
|
||||
#
|
||||
# Notes:
|
||||
# * This function is a no-op if Googletest is not found.
|
||||
# * test_name behaves as a standard CMake target, i.e. such operations as
|
||||
# target_compile_options, etc. are supported.
|
||||
#
|
||||
# Additional actions on test_name include:
|
||||
# * Target-specific definition PANDA_GTEST is added.
|
||||
# * Googletest-specific libraries are linked to test_name by default,
|
||||
# and there's no need to set them explicitly.
|
||||
|
||||
function(panda_add_gtest)
|
||||
if(NOT PANDA_WITH_TESTS)
|
||||
return()
|
||||
endif()
|
||||
if(NOT "OUTPUT_DIRECTORY" IN_LIST ARGV)
|
||||
list(APPEND ARGV "OUTPUT_DIRECTORY" "${PANDA_BINARY_ROOT}/bin-gtests")
|
||||
endif()
|
||||
common_add_gtest(ENCLOSING_TARGET gtests_build ${ARGV})
|
||||
endfunction()
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
# 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.
|
||||
|
||||
project(miniz)
|
||||
|
||||
add_library(miniz ${MINIZ_ROOT}/miniz.c)
|
||||
target_include_directories(miniz PUBLIC ${MINIZ_ROOT})
|
||||
|
||||
target_compile_options(miniz PUBLIC -Wno-return-type-c-linkage)
|
||||
|
||||
# NB! We always build miniz statically, but there seems
|
||||
# no obvious reasons for that. If we reconsider, the logic
|
||||
# below should be replaced with something like:
|
||||
#
|
||||
# add_library(miniz ${PANDA_DEFAULT_LIB_TYPE} miniz.c)
|
||||
#
|
||||
# **Besides** build of host tools should be fixed to
|
||||
# take into account new shared library
|
||||
if(NOT PANDA_TARGET_WINDOWS)
|
||||
target_compile_options(miniz PRIVATE -fPIC)
|
||||
endif()
|
||||
|
||||
if (PANDA_ENABLE_AFL)
|
||||
include("${PANDA_ROOT}/fuzzing/Fuzzing.cmake")
|
||||
panda_substitute_libs(TARGET miniz)
|
||||
endif()
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(securec)
|
||||
|
||||
set(SOURCES
|
||||
${SECUREC_ROOT}/src/vsprintf_s.c
|
||||
${SECUREC_ROOT}/src/wmemmove_s.c
|
||||
${SECUREC_ROOT}/src/strncat_s.c
|
||||
${SECUREC_ROOT}/src/vsnprintf_s.c
|
||||
${SECUREC_ROOT}/src/fwscanf_s.c
|
||||
${SECUREC_ROOT}/src/scanf_s.c
|
||||
${SECUREC_ROOT}/src/strcat_s.c
|
||||
${SECUREC_ROOT}/src/sscanf_s.c
|
||||
${SECUREC_ROOT}/src/secureprintoutput_w.c
|
||||
${SECUREC_ROOT}/src/wmemcpy_s.c
|
||||
${SECUREC_ROOT}/src/wcsncat_s.c
|
||||
${SECUREC_ROOT}/src/secureprintoutput_a.c
|
||||
${SECUREC_ROOT}/src/secureinput_w.c
|
||||
${SECUREC_ROOT}/src/memcpy_s.c
|
||||
${SECUREC_ROOT}/src/fscanf_s.c
|
||||
${SECUREC_ROOT}/src/vswscanf_s.c
|
||||
${SECUREC_ROOT}/src/secureinput_a.c
|
||||
${SECUREC_ROOT}/src/sprintf_s.c
|
||||
${SECUREC_ROOT}/src/memmove_s.c
|
||||
${SECUREC_ROOT}/src/swscanf_s.c
|
||||
${SECUREC_ROOT}/src/snprintf_s.c
|
||||
${SECUREC_ROOT}/src/vscanf_s.c
|
||||
${SECUREC_ROOT}/src/vswprintf_s.c
|
||||
${SECUREC_ROOT}/src/wcscpy_s.c
|
||||
${SECUREC_ROOT}/src/vfwscanf_s.c
|
||||
${SECUREC_ROOT}/src/memset_s.c
|
||||
${SECUREC_ROOT}/src/wscanf_s.c
|
||||
${SECUREC_ROOT}/src/vwscanf_s.c
|
||||
${SECUREC_ROOT}/src/strtok_s.c
|
||||
${SECUREC_ROOT}/src/wcsncpy_s.c
|
||||
${SECUREC_ROOT}/src/vfscanf_s.c
|
||||
${SECUREC_ROOT}/src/vsscanf_s.c
|
||||
${SECUREC_ROOT}/src/wcstok_s.c
|
||||
${SECUREC_ROOT}/src/securecutil.c
|
||||
${SECUREC_ROOT}/src/gets_s.c
|
||||
${SECUREC_ROOT}/src/swprintf_s.c
|
||||
${SECUREC_ROOT}/src/strcpy_s.c
|
||||
${SECUREC_ROOT}/src/wcscat_s.c
|
||||
${SECUREC_ROOT}/src/strncpy_s.c
|
||||
)
|
||||
|
||||
add_library(c_secshared ${PANDA_DEFAULT_LIB_TYPE} ${SOURCES})
|
||||
target_include_directories(c_secshared PUBLIC ${SECUREC_ROOT}/include)
|
||||
target_compile_definitions(c_secshared PRIVATE NDEBUG SECUREC_SUPPORT_STRTOLD=1)
|
||||
if (PANDA_TARGET_WINDOWS)
|
||||
target_compile_definitions(c_secshared PUBLIC _CRTBLD __LIBMSVCRT__)
|
||||
endif()
|
||||
target_compile_options(c_secshared PRIVATE -Wall -O1)
|
||||
|
||||
if (PANDA_ENABLE_AFL)
|
||||
add_library(c_secshared_fuzz ${PANDA_DEFAULT_LIB_TYPE} ${SOURCES})
|
||||
target_include_directories(c_secshared_fuzz PUBLIC ${SECUREC_ROOT}/include)
|
||||
target_compile_definitions(c_secshared_fuzz PRIVATE NDEBUG SECUREC_SUPPORT_STRTOLD=1)
|
||||
if (PANDA_TARGET_WINDOWS)
|
||||
target_compile_definitions(c_secshared_fuzz PUBLIC _CRTBLD __LIBMSVCRT__)
|
||||
endif()
|
||||
target_compile_options(c_secshared_fuzz PRIVATE -Wall -O1 --afl_noopt)
|
||||
endif()
|
||||
@@ -0,0 +1,75 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
project(PANDA_HOST LANGUAGES CXX)
|
||||
|
||||
set(PANDA_ROOT ${PANDA_ROOT_SOURCE_DIR})
|
||||
|
||||
# ----- Platform definitions ---------------------------------------------------
|
||||
include(${PANDA_ROOT_SOURCE_DIR}/cmake/Definitions.cmake)
|
||||
|
||||
# ----- Template Based Generator -----------------------------------------------
|
||||
include(${PANDA_ROOT_SOURCE_DIR}/cmake/TemplateBasedGen.cmake)
|
||||
|
||||
# ----- Default flags ----------------------------------------------------------
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Default common flags
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror")
|
||||
|
||||
# Additional flags for NORTTI
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
|
||||
|
||||
# ----- Panda CMake functions --------------------------------------------------
|
||||
include(${PANDA_ROOT_SOURCE_DIR}/cmake/PandaCmakeFunctions.cmake)
|
||||
|
||||
# ----- Stubs ------------------------------------------------------------------
|
||||
if(NOT COMMAND add_check_style)
|
||||
function(add_check_style)
|
||||
# Stub
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
if(NOT COMMAND panda_add_gtest)
|
||||
function(panda_add_gtest)
|
||||
# Stub
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
if(NOT COMMAND panda_add_sanitizers)
|
||||
function(panda_add_sanitizers)
|
||||
# Stub
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
if(NOT COMMAND panda_add_to_clang_tidy)
|
||||
function(panda_add_to_clang_tidy)
|
||||
#stub
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
# ----- Targets ----------------------------------------------------------------
|
||||
set(SECUREC_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/securec)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/securec ${CMAKE_CURRENT_BINARY_DIR}/third_party/libc_sec)
|
||||
|
||||
set(MINIZ_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/miniz/amalgamation)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/miniz ${CMAKE_CURRENT_BINARY_DIR}/third_party/miniz)
|
||||
|
||||
add_subdirectory(${PANDA_ROOT_SOURCE_DIR}/isa ${CMAKE_CURRENT_BINARY_DIR}/isa)
|
||||
add_subdirectory(${PANDA_ROOT_SOURCE_DIR}/libpandabase ${CMAKE_CURRENT_BINARY_DIR}/libpandabase)
|
||||
add_subdirectory(${PANDA_ROOT_SOURCE_DIR}/libziparchive ${CMAKE_CURRENT_BINARY_DIR}/libziparchive)
|
||||
add_subdirectory(${PANDA_ROOT_SOURCE_DIR}/libpandafile ${CMAKE_CURRENT_BINARY_DIR}/libpandafile)
|
||||
add_subdirectory(${PANDA_ROOT_SOURCE_DIR}/assembler ${CMAKE_CURRENT_BINARY_DIR}/assembler)
|
||||
@@ -0,0 +1,28 @@
|
||||
# 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(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
|
||||
set(ENV{AFL_CC_COMPILER} "LLVM")
|
||||
set(ENV{AFL_LLVM_LAF_ALL} "1")
|
||||
set(PANDA_ENABLE_CLANG_TIDY false CACHE BOOL "Enable clang-tidy checks during compilation" FORCE)
|
||||
|
||||
set_c_compiler(afl-clang-fast)
|
||||
set_cxx_compiler(afl-clang-fast++)
|
||||
|
||||
add_definitions(-DFUZZING_EXIT_ON_FAILED_ASSERT=1)
|
||||
add_definitions(-DFUZZING_EXIT_ON_FAILED_ASSERT_FOR="/libpandafile/,/libpandabase/")
|
||||
|
||||
set(PANDA_ENABLE_AFL true)
|
||||
set(PANDA_FUZZING_SANITIZERS false)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-stack-address")
|
||||
@@ -0,0 +1,50 @@
|
||||
# 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.
|
||||
# Common functions for add environment for compiling and cross-compiling.
|
||||
# Used by different toolchains.
|
||||
|
||||
function(set_c_compiler c_compiler_id)
|
||||
find_program(c_compiler ${c_compiler_id})
|
||||
if(NOT c_compiler)
|
||||
message(FATAL_ERROR "Unable to find C compiler ${c_compiler_id}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_COMPILER ${c_compiler} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(set_cxx_compiler cxx_compiler_id)
|
||||
find_program(cxx_compiler ${cxx_compiler_id})
|
||||
if(NOT cxx_compiler)
|
||||
message(FATAL_ERROR "Unable to find C++ compiler ${cxx_compiler_id}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_COMPILER ${cxx_compiler} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(set_cross_amd64_x86)
|
||||
if(NOT CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
||||
message(FATAL_ERROR "Unsupported host processor ${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
# Caveats about the code below:
|
||||
# * The "if" is needed because the toolchain file is parsed twice.
|
||||
# * add_compile_options is not used intentionally as it does not
|
||||
# propagate the options to the linker, which is needed.
|
||||
if (NOT PANDA_CROSS_AMD64_X86)
|
||||
set(PANDA_CROSS_AMD64_X86 1 CACHE STRING "" FORCE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "" FORCE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "" FORCE)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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.
|
||||
|
||||
set(PANDA_TRIPLET aarch64-linux-gnu)
|
||||
set(PANDA_SYSROOT /usr/${PANDA_TRIPLET})
|
||||
set(PANDA_RUN_PREFIX qemu-aarch64 -L ${PANDA_SYSROOT})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
set(CMAKE_PREFIX_PATH ${PANDA_SYSROOT})
|
||||
set(CMAKE_C_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
add_compile_options(
|
||||
-isystem ${PANDA_SYSROOT}/include/c++/8/${PANDA_TRIPLET}
|
||||
--sysroot=${PANDA_SYSROOT}
|
||||
--target=${PANDA_TRIPLET}
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-8)
|
||||
set_cxx_compiler(clang++-8)
|
||||
@@ -0,0 +1,34 @@
|
||||
# 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.
|
||||
|
||||
set(PANDA_TRIPLET arm-linux-gnueabi)
|
||||
set(PANDA_SYSROOT /usr/${PANDA_TRIPLET})
|
||||
set(PANDA_TARGET_ARM32_ABI_SOFT 1)
|
||||
set(PANDA_RUN_PREFIX qemu-arm -L ${PANDA_SYSROOT})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
set(CMAKE_PREFIX_PATH ${PANDA_SYSROOT})
|
||||
set(CMAKE_C_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
add_compile_options(
|
||||
-isystem ${PANDA_SYSROOT}/include/c++/8/${PANDA_TRIPLET}
|
||||
--sysroot=${PANDA_SYSROOT}
|
||||
--target=${PANDA_TRIPLET}
|
||||
-mfloat-abi=softfp
|
||||
-march=armv7
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-8)
|
||||
set_cxx_compiler(clang++-8)
|
||||
@@ -0,0 +1,34 @@
|
||||
# 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.
|
||||
|
||||
set(PANDA_TRIPLET arm-linux-gnueabihf)
|
||||
set(PANDA_SYSROOT /usr/${PANDA_TRIPLET})
|
||||
set(PANDA_TARGET_ARM32_ABI_HARD 1)
|
||||
set(PANDA_RUN_PREFIX qemu-arm -L ${PANDA_SYSROOT})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
set(CMAKE_PREFIX_PATH ${PANDA_SYSROOT})
|
||||
set(CMAKE_C_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
add_compile_options(
|
||||
-isystem ${PANDA_SYSROOT}/include/c++/8/${PANDA_TRIPLET}
|
||||
--sysroot=${PANDA_SYSROOT}
|
||||
--target=${PANDA_TRIPLET}
|
||||
-mfloat-abi=hard
|
||||
-march=armv7
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-8)
|
||||
set_cxx_compiler(clang++-8)
|
||||
@@ -0,0 +1,18 @@
|
||||
# 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(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-8)
|
||||
set_cxx_compiler(clang++-8)
|
||||
|
||||
set_cross_amd64_x86()
|
||||
@@ -0,0 +1,51 @@
|
||||
# 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.
|
||||
|
||||
set(PANDA_TRIPLET x86_64-w64-mingw32)
|
||||
set(PANDA_SYSROOT /usr/${PANDA_TRIPLET})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
set(CMAKE_PREFIX_PATH ${PANDA_SYSROOT})
|
||||
set(CMAKE_C_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
|
||||
# NB! Do not use "win32" threading model, it does not provide
|
||||
# std::thread and std::mutex. Use "posix" instead.
|
||||
set(MINGW_THREADING_MODEL posix)
|
||||
set(MINGW_CXX_BIN_NAME ${PANDA_TRIPLET}-g++-${MINGW_THREADING_MODEL})
|
||||
|
||||
find_program(MINGW_CXX_BIN ${MINGW_CXX_BIN_NAME})
|
||||
if("${MINGW_CXX_BIN}" STREQUAL "MINGW_CXX_BIN-NOTFOUND")
|
||||
message(FATAL_ERROR "Unable to find MinGW ${MINGW_CXX_BIN_NAME}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${MINGW_CXX_BIN} -dumpversion
|
||||
OUTPUT_VARIABLE MINGW_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
set(MINGW_CXX_INC /usr/lib/gcc/${PANDA_TRIPLET}/${MINGW_VERSION}/include/c++)
|
||||
|
||||
add_compile_options(
|
||||
-isystem ${MINGW_CXX_INC}
|
||||
-I ${MINGW_CXX_INC}/${PANDA_TRIPLET} # For #include <bits/...>
|
||||
--sysroot=${PANDA_SYSROOT}
|
||||
--target=${PANDA_TRIPLET}
|
||||
)
|
||||
|
||||
# NB! For Windows we link everything statically (incl. standard library, pthread, etc.):
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/lib/gcc/${PANDA_TRIPLET}/${MINGW_VERSION} -static-libstdc++ -static-libgcc -Wl,-Bstatic")
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-8)
|
||||
set_cxx_compiler(clang++-8)
|
||||
@@ -0,0 +1,31 @@
|
||||
# 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.
|
||||
|
||||
set(PANDA_TRIPLET aarch64-linux-gnu)
|
||||
set(PANDA_SYSROOT /usr/${PANDA_TRIPLET})
|
||||
set(PANDA_RUN_PREFIX qemu-aarch64 -L ${PANDA_SYSROOT})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
set(CMAKE_PREFIX_PATH ${PANDA_SYSROOT})
|
||||
set(CMAKE_C_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
add_compile_options(
|
||||
-isystem ${PANDA_SYSROOT}/include/c++/8/${PANDA_TRIPLET}
|
||||
--sysroot=${PANDA_SYSROOT}
|
||||
--target=${PANDA_TRIPLET}
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-9)
|
||||
set_cxx_compiler(clang++-9)
|
||||
@@ -0,0 +1,34 @@
|
||||
# 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.
|
||||
|
||||
set(PANDA_TRIPLET arm-linux-gnueabihf)
|
||||
set(PANDA_SYSROOT /usr/${PANDA_TRIPLET})
|
||||
set(PANDA_TARGET_ARM32_ABI_HARD 1)
|
||||
set(PANDA_RUN_PREFIX qemu-arm -L ${PANDA_SYSROOT})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
set(CMAKE_PREFIX_PATH ${PANDA_SYSROOT})
|
||||
set(CMAKE_C_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
add_compile_options(
|
||||
-isystem ${PANDA_SYSROOT}/include/c++/8/${PANDA_TRIPLET}
|
||||
--sysroot=${PANDA_SYSROOT}
|
||||
--target=${PANDA_TRIPLET}
|
||||
-mfloat-abi=hard
|
||||
-march=armv7
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-9)
|
||||
set_cxx_compiler(clang++-9)
|
||||
@@ -0,0 +1,18 @@
|
||||
# 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(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-9)
|
||||
set_cxx_compiler(clang++-9)
|
||||
|
||||
set_cross_amd64_x86()
|
||||
@@ -0,0 +1,51 @@
|
||||
# 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.
|
||||
|
||||
set(PANDA_TRIPLET x86_64-w64-mingw32)
|
||||
set(PANDA_SYSROOT /usr/${PANDA_TRIPLET})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
set(CMAKE_PREFIX_PATH ${PANDA_SYSROOT})
|
||||
set(CMAKE_C_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${PANDA_TRIPLET})
|
||||
|
||||
# NB! Do not use "win32" threading model, it does not provide
|
||||
# std::thread and std::mutex. Use "posix" instead.
|
||||
set(MINGW_THREADING_MODEL posix)
|
||||
set(MINGW_CXX_BIN_NAME ${PANDA_TRIPLET}-g++-${MINGW_THREADING_MODEL})
|
||||
|
||||
find_program(MINGW_CXX_BIN ${MINGW_CXX_BIN_NAME})
|
||||
if("${MINGW_CXX_BIN}" STREQUAL "MINGW_CXX_BIN-NOTFOUND")
|
||||
message(FATAL_ERROR "Unable to find MinGW ${MINGW_CXX_BIN_NAME}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${MINGW_CXX_BIN} -dumpversion
|
||||
OUTPUT_VARIABLE MINGW_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
set(MINGW_CXX_INC /usr/lib/gcc/${PANDA_TRIPLET}/${MINGW_VERSION}/include/c++)
|
||||
|
||||
add_compile_options(
|
||||
-isystem ${MINGW_CXX_INC}
|
||||
-I ${MINGW_CXX_INC}/${PANDA_TRIPLET} # For #include <bits/...>
|
||||
--sysroot=${PANDA_SYSROOT}
|
||||
--target=${PANDA_TRIPLET}
|
||||
)
|
||||
|
||||
# NB! For Windows we link everything statically (incl. standard library, pthread, etc.):
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/lib/gcc/${PANDA_TRIPLET}/${MINGW_VERSION} -static-libstdc++ -static-libgcc -Wl,-Bstatic")
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/common.cmake)
|
||||
set_c_compiler(clang-9)
|
||||
set_cxx_compiler(clang++-9)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user